From ea0fa07fa4fdc8c9f2395f711c5fc1f744220e49 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 15:43:04 -0300 Subject: [PATCH 01/49] add po message catalog implementation --- i18n/cmd/po/catalog.go | 79 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 i18n/cmd/po/catalog.go diff --git a/i18n/cmd/po/catalog.go b/i18n/cmd/po/catalog.go new file mode 100644 index 00000000000..bbe57fca6cb --- /dev/null +++ b/i18n/cmd/po/catalog.go @@ -0,0 +1,79 @@ +package po + +import ( + "fmt" + "io" + "sort" + "strings" +) + +type ( + MessageCatalog struct { + Messages map[string]*Message + } + + Message struct { + Comments []string + Value string + } +) + +func (catalog *MessageCatalog) Add(id, value string, comment []string) { + if catalog.Messages == nil { + catalog.Messages = map[string]*Message{} + } + + if catalog.Messages[id] == nil { + catalog.Messages[id] = &Message{Value: value} + } + + if len(comment) != 0 { + catalog.Messages[id].Comments = comment + } +} + +func (catalog *MessageCatalog) AddMessage(id string, message Message) { + catalog.Add(id, message.Value, message.Comments) +} + +func (catalog *MessageCatalog) SortedKeys() []string { + keys := []string{} + for k := range catalog.Messages { + keys = append(keys, k) + } + + sort.Strings(keys) + return keys +} + +func (catalog *MessageCatalog) Write(w io.Writer) { + keys := []string{} + for k := range catalog.Messages { + keys = append(keys, k) + } + + sort.Strings(keys) + + for _, k := range keys { + msg := catalog.Messages[k] + + for _, comment := range msg.Comments { + fmt.Fprintln(w, comment) + } + + printValue(w, "msgid", k) + printValue(w, "msgstr", msg.Value) + fmt.Fprintln(w) + } +} + +func printValue(w io.Writer, field, value string) { + if strings.Contains(value, "\n") { + fmt.Fprintf(w, "%s ", field) + for _, line := range strings.Split(value, "\n") { + fmt.Fprintf(w, "\"%s\"\n", strings.ReplaceAll(line, `"`, `\"`)) + } + } else { + fmt.Fprintf(w, "%s \"%s\"\n", field, strings.ReplaceAll(value, `"`, `\"`)) + } +} From 818c40d6afb9cd3cdbc0299cd0e7c233ead229a6 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 15:43:27 -0300 Subject: [PATCH 02/49] add po parser for i18n cmd --- i18n/cmd/po/parser.go | 110 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 i18n/cmd/po/parser.go diff --git a/i18n/cmd/po/parser.go b/i18n/cmd/po/parser.go new file mode 100644 index 00000000000..d9162a72724 --- /dev/null +++ b/i18n/cmd/po/parser.go @@ -0,0 +1,110 @@ +package po + +import ( + "bufio" + "fmt" + "os" + "strconv" + "strings" +) + +func Parse(filename string) MessageCatalog { + if !fileExists(filename) { + return MessageCatalog{} + } + + file, err := os.Open(filename) + + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + scanner := bufio.NewScanner(file) + return parseCatalog(scanner) +} + +func parseCatalog(scanner *bufio.Scanner) MessageCatalog { + const ( + StateWhitespace = 0 + StateComment = 1 + StateMessageID = 2 + StateMessageValue = 3 + ) + + state := StateWhitespace + catalog := MessageCatalog{} + comments := []string{} + id := "" + value := "" + for { + more := scanner.Scan() + + if !more { + if state != StateWhitespace { + catalog.Add(id, value, comments) + } + break + } + + line := scanner.Text() + + if state == StateWhitespace && strings.TrimSpace(line) == "" { + continue + } else if state != StateWhitespace && strings.TrimSpace(line) == "" { + catalog.Add(id, value, comments) + state = StateWhitespace + id = "" + value = "" + comments = []string{} + continue + } + + if strings.HasPrefix(line, "#") { + state = StateComment + comments = append(comments, line) + continue + } + + if strings.HasPrefix(line, "msgid") { + state = StateMessageID + id += mustUnquote(strings.TrimLeft(line, "msgid ")) + continue + } + + if state == StateMessageID && strings.HasPrefix(line, "\"") { + id += "\n" + mustUnquote(line) + continue + } + + if strings.HasPrefix(line, "msgstr") { + state = StateMessageValue + value += mustUnquote(strings.TrimLeft(line, "msgstr ")) + continue + } + + if state == StateMessageValue && strings.HasPrefix(line, "\"") { + value += "\n" + mustUnquote(line) + continue + } + } + + return catalog +} + +func mustUnquote(line string) string { + v, err := strconv.Unquote(line) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + return v +} + +func fileExists(filename string) bool { + info, err := os.Stat(filename) + if os.IsNotExist(err) { + return false + } + return !info.IsDir() +} From d1103c29c22cbe9916082021c54a2644d4a06da7 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 15:43:46 -0300 Subject: [PATCH 03/49] add po merge function --- i18n/cmd/po/merge.go | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 i18n/cmd/po/merge.go diff --git a/i18n/cmd/po/merge.go b/i18n/cmd/po/merge.go new file mode 100644 index 00000000000..c79d6662d98 --- /dev/null +++ b/i18n/cmd/po/merge.go @@ -0,0 +1,26 @@ +package po + +func Merge(source MessageCatalog, destination MessageCatalog) MessageCatalog { + catalog := MessageCatalog{} + for _, k := range source.SortedKeys() { + if k == "" { + sourceMessage := source.Messages[k] + destinationMessage := destination.Messages[k] + + if destinationMessage != nil { + catalog.AddMessage(k, *destinationMessage) + } else { + catalog.AddMessage(k, *sourceMessage) + } + + continue + } + + if destination.Messages[k] != nil { + catalog.Add(k, destination.Messages[k].Value, source.Messages[k].Comments) + } else { + catalog.Add(k, "", source.Messages[k].Comments) + } + } + return catalog +} From d9f989e1ae4a7b6847ed956ae70f724c80a10a6d Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 15:45:25 -0300 Subject: [PATCH 04/49] add command to generate en po file from source --- i18n/cmd/ast/parser.go | 80 +++++++++++++++++++ i18n/cmd/commands/catalog/catalog.go | 12 +++ i18n/cmd/commands/catalog/generate_catalog.go | 20 +++++ i18n/cmd/commands/root.go | 19 +++++ i18n/cmd/main.go | 15 ++++ 5 files changed, 146 insertions(+) create mode 100644 i18n/cmd/ast/parser.go create mode 100644 i18n/cmd/commands/catalog/catalog.go create mode 100644 i18n/cmd/commands/catalog/generate_catalog.go create mode 100644 i18n/cmd/commands/root.go create mode 100644 i18n/cmd/main.go diff --git a/i18n/cmd/ast/parser.go b/i18n/cmd/ast/parser.go new file mode 100644 index 00000000000..63e1fb2943f --- /dev/null +++ b/i18n/cmd/ast/parser.go @@ -0,0 +1,80 @@ +package ast + +import ( + "fmt" + "go/ast" + "go/parser" + "go/token" + "os" + "strconv" + + "github.com/arduino/arduino-cli/i18n/cmd/po" +) + +func GenerateCatalog(files []string) po.MessageCatalog { + fset := token.NewFileSet() + catalog := po.MessageCatalog{} + + for _, file := range files { + node, err := parser.ParseFile(fset, file, nil, parser.AllErrors) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + doFile(fset, node, &catalog) + } + + catalog.Add("", "", nil) + + return catalog +} + +func doFile(fset *token.FileSet, file *ast.File, catalog *po.MessageCatalog) { + ast.Inspect(file, func(node ast.Node) bool { + funcCall, ok := node.(*ast.CallExpr) + + if !ok { + return true + } + + if functionName(funcCall) != "i18n.Tr" { + return true + } + + pos := fset.Position(funcCall.Pos()) + firstArg, ok := funcCall.Args[0].(*ast.BasicLit) + if !ok { + fmt.Fprintf(os.Stderr, "%s:%d\n", pos.Filename, pos.Line) + fmt.Fprintln(os.Stderr, "argument to i18n.Tr must be a literal string") + return true + } + + msg, err := strconv.Unquote(firstArg.Value) + + if err != nil { + fmt.Fprintf(os.Stderr, "%s:%d\n", pos.Filename, pos.Line) + fmt.Fprintln(os.Stderr, err.Error()) + return true + } + + catalog.Add(msg, msg, []string{fmt.Sprintf("#: %s:%d", pos.Filename, pos.Line)}) + + return true + }) +} + +func functionName(callExpr *ast.CallExpr) string { + + if iden, ok := callExpr.Fun.(*ast.Ident); ok { + return iden.Name + } + + if sel, ok := callExpr.Fun.(*ast.SelectorExpr); ok { + if iden, ok := sel.X.(*ast.Ident); ok { + return iden.Name + "." + sel.Sel.Name + } + } + + return "" +} diff --git a/i18n/cmd/commands/catalog/catalog.go b/i18n/cmd/commands/catalog/catalog.go new file mode 100644 index 00000000000..d30f9a8abb1 --- /dev/null +++ b/i18n/cmd/commands/catalog/catalog.go @@ -0,0 +1,12 @@ +package catalog + +import "github.com/spf13/cobra" + +var Command = &cobra.Command{ + Use: "catalog", + Short: "catalog", +} + +func init() { + Command.AddCommand(generateCatalogCommand) +} diff --git a/i18n/cmd/commands/catalog/generate_catalog.go b/i18n/cmd/commands/catalog/generate_catalog.go new file mode 100644 index 00000000000..197ebe16c2b --- /dev/null +++ b/i18n/cmd/commands/catalog/generate_catalog.go @@ -0,0 +1,20 @@ +package catalog + +import ( + "os" + + "github.com/arduino/arduino-cli/i18n/cmd/ast" + "github.com/spf13/cobra" +) + +var generateCatalogCommand = &cobra.Command{ + Use: "generate [source files]", + Short: "generates the en catalog from source files", + Args: cobra.MinimumNArgs(1), + Run: generateCatalog, +} + +func generateCatalog(cmd *cobra.Command, args []string) { + catalog := ast.GenerateCatalog(args) + catalog.Write(os.Stdout) +} diff --git a/i18n/cmd/commands/root.go b/i18n/cmd/commands/root.go new file mode 100644 index 00000000000..e9de74229c4 --- /dev/null +++ b/i18n/cmd/commands/root.go @@ -0,0 +1,19 @@ +package commands + +import ( + "github.com/arduino/arduino-cli/i18n/cmd/commands/catalog" + "github.com/spf13/cobra" +) + +var i18nCommand = &cobra.Command{ + Use: "i18n", + Short: "i18n", +} + +func init() { + i18nCommand.AddCommand(catalog.Command) +} + +func Execute() error { + return i18nCommand.Execute() +} diff --git a/i18n/cmd/main.go b/i18n/cmd/main.go new file mode 100644 index 00000000000..bf418cdb438 --- /dev/null +++ b/i18n/cmd/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "fmt" + "os" + + "github.com/arduino/arduino-cli/i18n/cmd/commands" +) + +func main() { + if err := commands.Execute(); err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } +} From 4fe2df21ec20929a30a466b15cf3626b698668f8 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 15:45:55 -0300 Subject: [PATCH 05/49] add command to update local po files with en catalog change --- i18n/cmd/commands/catalog/catalog.go | 1 + i18n/cmd/commands/catalog/update_catalog.go | 46 +++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 i18n/cmd/commands/catalog/update_catalog.go diff --git a/i18n/cmd/commands/catalog/catalog.go b/i18n/cmd/commands/catalog/catalog.go index d30f9a8abb1..a915ad53537 100644 --- a/i18n/cmd/commands/catalog/catalog.go +++ b/i18n/cmd/commands/catalog/catalog.go @@ -9,4 +9,5 @@ var Command = &cobra.Command{ func init() { Command.AddCommand(generateCatalogCommand) + Command.AddCommand(updateCatalogCommand) } diff --git a/i18n/cmd/commands/catalog/update_catalog.go b/i18n/cmd/commands/catalog/update_catalog.go new file mode 100644 index 00000000000..8b6f187b2a8 --- /dev/null +++ b/i18n/cmd/commands/catalog/update_catalog.go @@ -0,0 +1,46 @@ +package catalog + +import ( + "fmt" + "os" + "path" + + "github.com/arduino/arduino-cli/i18n/cmd/po" + "github.com/spf13/cobra" +) + +var updateCatalogCommand = &cobra.Command{ + Use: "update -l pt_BR [catalog folder]", + Short: "updates the language catalogs base on changes to the en catalog", + Args: cobra.ExactArgs(1), + Run: updateCatalog, +} + +var languages = []string{} + +func init() { + updateCatalogCommand.Flags().StringSliceVarP(&languages, "languages", "l", nil, "languages") + updateCatalogCommand.MarkFlagRequired("languages") +} + +func updateCatalog(cmd *cobra.Command, args []string) { + folder := args[0] + enCatalog := po.Parse(path.Join(folder, "en.po")) + + for _, lang := range languages { + filename := path.Join(folder, fmt.Sprintf("%s.po", lang)) + langCatalog := po.Parse(filename) + + mergedCatalog := po.Merge(enCatalog, langCatalog) + + os.Remove(filename) + file, err := os.OpenFile(path.Join(folder, fmt.Sprintf("%s.po", lang)), os.O_CREATE|os.O_RDWR, 0644) + + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + mergedCatalog.Write(file) + } +} From 6b6d237b64a04a0b81e0cbdd8be42ede7ff897e4 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 15:47:19 -0300 Subject: [PATCH 06/49] add task to generate po files --- Taskfile.yml | 8 ++++++++ i18n/data/.gitkeep | 0 2 files changed, 8 insertions(+) create mode 100644 i18n/data/.gitkeep diff --git a/Taskfile.yml b/Taskfile.yml index 64282302b55..2e0f36708fc 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -114,6 +114,13 @@ tasks: cmds: - go test -run TestWithClientE2E ./commands/daemon + i18n:update: + desc: Updates i18n files + cmds: + - go build -o i18n-cli ./i18n/cmd/main.go + - find . -type f -name "*.go" | xargs go run ./i18n/cmd/main.go catalog generate > ./i18n/data/en.po + - go run ./i18n/cmd/main.go catalog update -l {{.I18N_LANGS}} ./i18n/data + vars: # all modules of this project except for "legacy/..." module DEFAULT_TARGETS: @@ -138,3 +145,4 @@ vars: DOCS_VERSION: dev DOCS_ALIAS: "" DOCS_REMOTE: "origin" + I18N_LANGS: "pt_BR" diff --git a/i18n/data/.gitkeep b/i18n/data/.gitkeep new file mode 100644 index 00000000000..e69de29bb2d From fcd00829494987080c441a05a87999e94679f060 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 16:41:03 -0300 Subject: [PATCH 07/49] add locale option for i18n --- Taskfile.yml | 1 + cli/cli.go | 4 ++++ i18n/i18n.go | 7 +++++++ i18n/locale.go | 33 +++++++++++++++++++++++++++++++++ 4 files changed, 45 insertions(+) create mode 100644 i18n/i18n.go create mode 100644 i18n/locale.go diff --git a/Taskfile.yml b/Taskfile.yml index 2e0f36708fc..1dc7d6ff71b 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -120,6 +120,7 @@ tasks: - go build -o i18n-cli ./i18n/cmd/main.go - find . -type f -name "*.go" | xargs go run ./i18n/cmd/main.go catalog generate > ./i18n/data/en.po - go run ./i18n/cmd/main.go catalog update -l {{.I18N_LANGS}} ./i18n/data + - go generate ./i18n vars: # all modules of this project except for "legacy/..." module diff --git a/cli/cli.go b/cli/cli.go index 653aaff6d04..59430a9323b 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -39,6 +39,7 @@ import ( "github.com/arduino/arduino-cli/cli/upload" "github.com/arduino/arduino-cli/cli/version" "github.com/arduino/arduino-cli/configuration" + "github.com/arduino/arduino-cli/i18n" "github.com/arduino/arduino-cli/inventory" "github.com/mattn/go-colorable" "github.com/rifflock/lfshook" @@ -168,6 +169,9 @@ func preRun(cmd *cobra.Command, args []string) { configuration.Init(configPath) configFile := viper.ConfigFileUsed() + // initialize locale + i18n.SetLocale(viper.GetString("locale")) + // initialize inventory inventory.Init(viper.GetString("directories.Data")) diff --git a/i18n/i18n.go b/i18n/i18n.go new file mode 100644 index 00000000000..b0ee23c4cc2 --- /dev/null +++ b/i18n/i18n.go @@ -0,0 +1,7 @@ +package i18n + +// Tr returns msg translated to the selected locale +// the msg argument must be a literal string +func Tr(msg string, args ...interface{}) string { + return po.Get(msg, args...) +} diff --git a/i18n/locale.go b/i18n/locale.go new file mode 100644 index 00000000000..42bdb32ce2d --- /dev/null +++ b/i18n/locale.go @@ -0,0 +1,33 @@ +package i18n + +//go:generate rice embed-go + +import ( + "sync" + + rice "github.com/GeertJohan/go.rice" + "github.com/leonelquinteros/gotext" + "github.com/sirupsen/logrus" +) + +var ( + loadOnce sync.Once + po *gotext.Po +) + +func init() { + po = new(gotext.Po) +} + +func SetLocale(locale string) { + box := rice.MustFindBox("./data") + poFile, err := box.Bytes(locale + ".po") + + if err != nil { + logrus.Warn("i18n not found for ", locale, " using en") + poFile = box.MustBytes("en.po") + } + + po = new(gotext.Po) + po.Parse(poFile) +} From 602cd54feb0552954f22e841b8303d60bf6f0cf6 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 16:42:09 -0300 Subject: [PATCH 08/49] add dependencies for i18n --- go.mod | 2 ++ go.sum | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) diff --git a/go.mod b/go.mod index 758841d14bd..fa398bf170e 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,7 @@ go 1.14 require ( bou.ke/monkey v1.0.1 + github.com/GeertJohan/go.rice v1.0.0 github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c github.com/arduino/go-paths-helper v1.0.1 github.com/arduino/go-properties-orderedmap v1.0.0 @@ -23,6 +24,7 @@ require ( github.com/juju/errors v0.0.0-20181118221551-089d3ea4e4d5 // indirect github.com/juju/loggo v0.0.0-20190526231331-6e530bcce5d8 // indirect github.com/juju/testing v0.0.0-20190429233213-dfc56b8c09fc // indirect + github.com/leonelquinteros/gotext v1.4.0 github.com/mattn/go-colorable v0.1.2 github.com/mattn/go-runewidth v0.0.2 // indirect github.com/miekg/dns v1.0.5 // indirect diff --git a/go.sum b/go.sum index d32bee8d0ec..52b9bdc331c 100644 --- a/go.sum +++ b/go.sum @@ -3,7 +3,13 @@ bou.ke/monkey v1.0.1/go.mod h1:FgHuK96Rv2Nlf+0u1OOVDpCMdsWyOFmeeketDHE7LIg= cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/GeertJohan/go.incremental v1.0.0 h1:7AH+pY1XUgQE4Y1HcXYaMqAI0m9yrFqo/jt0CW30vsg= +github.com/GeertJohan/go.incremental v1.0.0/go.mod h1:6fAjUhbVuX1KcMD3c8TEgVUqmo4seqhv0i0kdATSkM0= +github.com/GeertJohan/go.rice v1.0.0 h1:KkI6O9uMaQU3VEKaj01ulavtF7o1fWT7+pk/4voiMLQ= +github.com/GeertJohan/go.rice v1.0.0/go.mod h1:eH6gbSOAUv07dQuZVnBmoDP8mgsM1rtixis4Tib9if0= github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/akavel/rsrc v0.8.0 h1:zjWn7ukO9Kc5Q62DOJCcxGpXC18RawVtYAGdz2aLlfw= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/arduino/board-discovery v0.0.0-20180823133458-1ba29327fb0c h1:agh2JT96G8egU7FEb13L4dq3fnCN7lxXhJ86t69+W7s= @@ -38,6 +44,8 @@ github.com/cpuguy83/go-md2man v1.0.10 h1:BSKMNlYxDvnunlTymqtgONjNnaRV1sTpcovwwjF github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= github.com/creack/goselect v0.1.1 h1:tiSSgKE1eJtxs1h/VgGQWuXUP0YS4CDIFMp6vaI1ls0= github.com/creack/goselect v0.1.1/go.mod h1:a/NhLweNvqIYMuxcMOuWY516Cimucms3DglDzQP3hKY= +github.com/daaku/go.zipexe v1.0.0 h1:VSOgZtH418pH9L16hC/JrgSNJbbAL26pj7lmD1+CGdY= +github.com/daaku/go.zipexe v1.0.0/go.mod h1:z8IiR6TsVLEYKwXAoE/I+8ys/sDkgTzSL0CLnGVd57E= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -89,6 +97,8 @@ github.com/imjasonmiller/godice v0.1.2 h1:T1/sW/HoDzFeuwzOOuQjmeMELz9CzZ53I2CnD+ github.com/imjasonmiller/godice v0.1.2/go.mod h1:8cTkdnVI+NglU2d6sv+ilYcNaJ5VSTBwvMbFULJd/QQ= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jessevdk/go-flags v1.4.0 h1:4IU2WS7AumrZ/40jfhf4QVDMsQwqA7VEHozFRrGARJA= +github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= @@ -109,6 +119,8 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/leonelquinteros/gotext v1.4.0 h1:2NHPCto5IoMXbrT0bldPrxj0qM5asOCwtb1aUQZ1tys= +github.com/leonelquinteros/gotext v1.4.0/go.mod h1:yZGXREmoGTtBvZHNcc+Yfug49G/2spuF/i/Qlsvz1Us= github.com/magiconair/properties v1.8.0 h1:LLgXmsheXeRoUOBOjtwPQCWIYqM/LU1ayDtDePerRcY= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1 h1:ZC2Vc7/ZFkGmsVC9KvOjumD+G5lXy2RtTKyzRKO2BQ4= @@ -130,6 +142,8 @@ github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrk github.com/mitchellh/mapstructure v1.1.2 h1:fmNYVwqnSfB9mZU6OS2O6GsXM+wcskZDuKQzvN1EDeE= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229 h1:E2B8qYyeSgv5MXpmzZXRNp8IAQ4vjxIjhpAf5hv/tAg= +github.com/nkovacs/streamquote v0.0.0-20170412213628-49af9bddb229/go.mod h1:0aYXnNPJ8l7uZxf45rWW1a/uME32OF0rhiYGNQ2oF2E= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/oleksandr/bonjour v0.0.0-20160508152359-5dcf00d8b228 h1:Cvfd2dOlXIPTeEkOT/h8PyK4phBngOM4at9/jlgy7d4= github.com/oleksandr/bonjour v0.0.0-20160508152359-5dcf00d8b228/go.mod h1:MGuVJ1+5TX1SCoO2Sx0eAnjpdRytYla2uC1YIZfkC9c= @@ -201,6 +215,10 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= github.com/ugorji/go v1.1.4/go.mod h1:uQMGLiO92mf5W77hV/PUCpI3pbzQx3CRekS0kk+RGrc= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw= +github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc= +github.com/valyala/fasttemplate v1.0.1 h1:tY9CJiPnMXf1ERmG2EyK7gNUd+c6RKGD0IfU8WdUSz8= +github.com/valyala/fasttemplate v1.0.1/go.mod h1:UQGH1tvbgY+Nz5t2n7tXsz52dQxojPUpymEIMZ47gx8= github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.bug.st/cleanup v1.0.0 h1:XVj1HZxkBXeq3gMT7ijWUpHyIC1j8XAoNSyQ06CskgA= From 46cacf2531fddc62ce168913f06645d0adbe8fe0 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 16:42:37 -0300 Subject: [PATCH 09/49] add unit test for i18n --- i18n/i18n_test.go | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 i18n/i18n_test.go diff --git a/i18n/i18n_test.go b/i18n/i18n_test.go new file mode 100644 index 00000000000..15fd99979cf --- /dev/null +++ b/i18n/i18n_test.go @@ -0,0 +1,36 @@ +package i18n + +import ( + "testing" + + "github.com/leonelquinteros/gotext" + "github.com/stretchr/testify/require" +) + +func setPo(poFile string) { + po = new(gotext.Po) + po.Parse([]byte(poFile)) +} + +func TestPoTranslation(t *testing.T) { + setPo(` + msgid "test-key-ok" + msgstr "test-key-translated" + `) + require.Equal(t, "test-key", Tr("test-key")) + require.Equal(t, "test-key-translated", Tr("test-key-ok")) +} + +func TestNoLocaleSet(t *testing.T) { + po = new(gotext.Po) + require.Equal(t, "test-key", Tr("test-key")) +} + +func TestTranslationWithVariables(t *testing.T) { + setPo(` + msgid "test-key-ok %s" + msgstr "test-key-translated %s" + `) + require.Equal(t, "test-key", Tr("test-key")) + require.Equal(t, "test-key-translated message", Tr("test-key-ok %s", "message")) +} From a203de51fbee0559d7199ddd23ab785f87e25a3f Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 16:57:48 -0300 Subject: [PATCH 10/49] add godoc to exported fields --- i18n/cmd/ast/parser.go | 1 + i18n/cmd/commands/catalog/catalog.go | 1 + i18n/cmd/commands/root.go | 1 + i18n/cmd/po/catalog.go | 6 ++++++ i18n/cmd/po/merge.go | 1 + i18n/cmd/po/parser.go | 1 + i18n/locale.go | 1 + 7 files changed, 12 insertions(+) diff --git a/i18n/cmd/ast/parser.go b/i18n/cmd/ast/parser.go index 63e1fb2943f..08694d2ac9c 100644 --- a/i18n/cmd/ast/parser.go +++ b/i18n/cmd/ast/parser.go @@ -11,6 +11,7 @@ import ( "github.com/arduino/arduino-cli/i18n/cmd/po" ) +// GenerateCatalog generates the i18n message catalog for the go source files func GenerateCatalog(files []string) po.MessageCatalog { fset := token.NewFileSet() catalog := po.MessageCatalog{} diff --git a/i18n/cmd/commands/catalog/catalog.go b/i18n/cmd/commands/catalog/catalog.go index a915ad53537..3e12e850494 100644 --- a/i18n/cmd/commands/catalog/catalog.go +++ b/i18n/cmd/commands/catalog/catalog.go @@ -2,6 +2,7 @@ package catalog import "github.com/spf13/cobra" +// Command is the catalog command var Command = &cobra.Command{ Use: "catalog", Short: "catalog", diff --git a/i18n/cmd/commands/root.go b/i18n/cmd/commands/root.go index e9de74229c4..2b1c5418853 100644 --- a/i18n/cmd/commands/root.go +++ b/i18n/cmd/commands/root.go @@ -14,6 +14,7 @@ func init() { i18nCommand.AddCommand(catalog.Command) } +// Execute executes the i18n command func Execute() error { return i18nCommand.Execute() } diff --git a/i18n/cmd/po/catalog.go b/i18n/cmd/po/catalog.go index bbe57fca6cb..b4e91c800de 100644 --- a/i18n/cmd/po/catalog.go +++ b/i18n/cmd/po/catalog.go @@ -8,16 +8,19 @@ import ( ) type ( + // MessageCatalog is the catalog of i18n messages for a given locale MessageCatalog struct { Messages map[string]*Message } + // Message represents a i18n message Message struct { Comments []string Value string } ) +// Add adds a new message in the i18n catalog func (catalog *MessageCatalog) Add(id, value string, comment []string) { if catalog.Messages == nil { catalog.Messages = map[string]*Message{} @@ -32,10 +35,12 @@ func (catalog *MessageCatalog) Add(id, value string, comment []string) { } } +// AddMessage adds a new message in the i18n catalog func (catalog *MessageCatalog) AddMessage(id string, message Message) { catalog.Add(id, message.Value, message.Comments) } +// SortedKeys returns the sorted keys in the catalog func (catalog *MessageCatalog) SortedKeys() []string { keys := []string{} for k := range catalog.Messages { @@ -46,6 +51,7 @@ func (catalog *MessageCatalog) SortedKeys() []string { return keys } +// Write writes the catalog in PO file format into w func (catalog *MessageCatalog) Write(w io.Writer) { keys := []string{} for k := range catalog.Messages { diff --git a/i18n/cmd/po/merge.go b/i18n/cmd/po/merge.go index c79d6662d98..7817eb0d872 100644 --- a/i18n/cmd/po/merge.go +++ b/i18n/cmd/po/merge.go @@ -1,5 +1,6 @@ package po +// Merge merges two message catalogs, preserving only keys present in source func Merge(source MessageCatalog, destination MessageCatalog) MessageCatalog { catalog := MessageCatalog{} for _, k := range source.SortedKeys() { diff --git a/i18n/cmd/po/parser.go b/i18n/cmd/po/parser.go index d9162a72724..8e102446ac7 100644 --- a/i18n/cmd/po/parser.go +++ b/i18n/cmd/po/parser.go @@ -8,6 +8,7 @@ import ( "strings" ) +// Parse parses the PO file into a MessageCatalog func Parse(filename string) MessageCatalog { if !fileExists(filename) { return MessageCatalog{} diff --git a/i18n/locale.go b/i18n/locale.go index 42bdb32ce2d..e659bdf2867 100644 --- a/i18n/locale.go +++ b/i18n/locale.go @@ -19,6 +19,7 @@ func init() { po = new(gotext.Po) } +// SetLocale sets the locate used for i18n func SetLocale(locale string) { box := rice.MustFindBox("./data") poFile, err := box.Bytes(locale + ".po") From 0c7be38eafe345f2725b0f4ebbfc07f4dda4f0e5 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 17:01:29 -0300 Subject: [PATCH 11/49] add rice box for i18n messages --- Taskfile.yml | 1 - i18n/data/en.po | 3 +++ i18n/data/pt_BR.po | 3 +++ i18n/rice-box.go | 59 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 65 insertions(+), 1 deletion(-) create mode 100644 i18n/data/en.po create mode 100644 i18n/data/pt_BR.po create mode 100644 i18n/rice-box.go diff --git a/Taskfile.yml b/Taskfile.yml index 1dc7d6ff71b..bfaf3343a3f 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -117,7 +117,6 @@ tasks: i18n:update: desc: Updates i18n files cmds: - - go build -o i18n-cli ./i18n/cmd/main.go - find . -type f -name "*.go" | xargs go run ./i18n/cmd/main.go catalog generate > ./i18n/data/en.po - go run ./i18n/cmd/main.go catalog update -l {{.I18N_LANGS}} ./i18n/data - go generate ./i18n diff --git a/i18n/data/en.po b/i18n/data/en.po new file mode 100644 index 00000000000..3af2658d218 --- /dev/null +++ b/i18n/data/en.po @@ -0,0 +1,3 @@ +msgid "" +msgstr "" + diff --git a/i18n/data/pt_BR.po b/i18n/data/pt_BR.po new file mode 100644 index 00000000000..3af2658d218 --- /dev/null +++ b/i18n/data/pt_BR.po @@ -0,0 +1,3 @@ +msgid "" +msgstr "" + diff --git a/i18n/rice-box.go b/i18n/rice-box.go new file mode 100644 index 00000000000..f015a759077 --- /dev/null +++ b/i18n/rice-box.go @@ -0,0 +1,59 @@ +package i18n + +import ( + "time" + + "github.com/GeertJohan/go.rice/embedded" +) + +func init() { + + // define files + file2 := &embedded.EmbeddedFile{ + Filename: ".gitkeep", + FileModTime: time.Unix(1587752852, 0), + + Content: string(""), + } + file3 := &embedded.EmbeddedFile{ + Filename: "en.po", + FileModTime: time.Unix(1587758440, 0), + + Content: string("msgid \"\"\nmsgstr \"\"\n\n"), + } + file4 := &embedded.EmbeddedFile{ + Filename: "pt_BR.po", + FileModTime: time.Unix(1587758441, 0), + + Content: string("msgid \"\"\nmsgstr \"\"\n\n"), + } + + // define dirs + dir1 := &embedded.EmbeddedDir{ + Filename: "", + DirModTime: time.Unix(1587758441, 0), + ChildFiles: []*embedded.EmbeddedFile{ + file2, // ".gitkeep" + file3, // "en.po" + file4, // "pt_BR.po" + + }, + } + + // link ChildDirs + dir1.ChildDirs = []*embedded.EmbeddedDir{} + + // register embeddedBox + embedded.RegisterEmbeddedBox(`./data`, &embedded.EmbeddedBox{ + Name: `./data`, + Time: time.Unix(1587758441, 0), + Dirs: map[string]*embedded.EmbeddedDir{ + "": dir1, + }, + Files: map[string]*embedded.EmbeddedFile{ + ".gitkeep": file2, + "en.po": file3, + "pt_BR.po": file4, + }, + }) +} From 19dc9eff25b54e768351496a983b6f83dddf04f1 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 17:10:37 -0300 Subject: [PATCH 12/49] add readme for i18n module --- i18n/README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 i18n/README.md diff --git a/i18n/README.md b/i18n/README.md new file mode 100644 index 00000000000..65e21350e82 --- /dev/null +++ b/i18n/README.md @@ -0,0 +1,13 @@ +# I18N + +## Usage + +In the source code, use the function `i18n.Tr("message", ...args)` to get a localized string. This tool parses the source using the `go/ast` package to generate the `en` locale using these messages. + +## Updating messages to reflect code changes + +The following command updates the locales present in the source code to reflect addition/removal of messages. + +```sh +task i18n:update +``` \ No newline at end of file From 484ae8a02551634962c88224675ba4170cd943f3 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 17:18:11 -0300 Subject: [PATCH 13/49] update README to add instruction to install go-rice --- i18n/README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/i18n/README.md b/i18n/README.md index 65e21350e82..37dd333b6ad 100644 --- a/i18n/README.md +++ b/i18n/README.md @@ -6,6 +6,13 @@ In the source code, use the function `i18n.Tr("message", ...args)` to get a loca ## Updating messages to reflect code changes +Install [go-rice](https://github.com/GeertJohan/go.rice) + +```sh +go get github.com/GeertJohan/go.rice +go get github.com/GeertJohan/go.rice/rice +``` + The following command updates the locales present in the source code to reflect addition/removal of messages. ```sh From c9ac6b19ea0683c5da06f3d7bc599c0ed4885cce Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 24 Apr 2020 17:47:55 -0300 Subject: [PATCH 14/49] remove warning log in case locale is not found --- i18n/locale.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/i18n/locale.go b/i18n/locale.go index e659bdf2867..b212f23d068 100644 --- a/i18n/locale.go +++ b/i18n/locale.go @@ -7,7 +7,6 @@ import ( rice "github.com/GeertJohan/go.rice" "github.com/leonelquinteros/gotext" - "github.com/sirupsen/logrus" ) var ( @@ -25,7 +24,6 @@ func SetLocale(locale string) { poFile, err := box.Bytes(locale + ".po") if err != nil { - logrus.Warn("i18n not found for ", locale, " using en") poFile = box.MustBytes("en.po") } From d3b957cba9b7e22e74fbaec4177c4cade2a17c06 Mon Sep 17 00:00:00 2001 From: Henrique Date: Wed, 6 May 2020 01:30:23 -0300 Subject: [PATCH 15/49] add command to pull and push translation files from/to transifex --- Taskfile.yml | 11 +++ cli/instance/instance.go | 1 + i18n/cmd/commands/root.go | 2 + i18n/cmd/commands/transifex/pull_transifex.go | 69 +++++++++++++++ i18n/cmd/commands/transifex/push_transifex.go | 86 +++++++++++++++++++ i18n/cmd/commands/transifex/transifex.go | 51 +++++++++++ 6 files changed, 220 insertions(+) create mode 100644 i18n/cmd/commands/transifex/pull_transifex.go create mode 100644 i18n/cmd/commands/transifex/push_transifex.go create mode 100644 i18n/cmd/commands/transifex/transifex.go diff --git a/Taskfile.yml b/Taskfile.yml index bfaf3343a3f..fc9eadfa695 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -121,6 +121,17 @@ tasks: - go run ./i18n/cmd/main.go catalog update -l {{.I18N_LANGS}} ./i18n/data - go generate ./i18n + i18n:pull: + desc: Pull i18n files from transifex + cmds: + - go run ./i18n/cmd/main.go transifex pull -l {{.I18N_LANGS}} ./i18n/data + - go generate ./i18n + + i18n:push: + desc: Push i18n files to transifex + cmds: + - go run ./i18n/cmd/main.go transifex push -l {{.I18N_LANGS}} ./i18n/data + vars: # all modules of this project except for "legacy/..." module DEFAULT_TARGETS: diff --git a/cli/instance/instance.go b/cli/instance/instance.go index 37c0d355323..0f7d8fa4243 100644 --- a/cli/instance/instance.go +++ b/cli/instance/instance.go @@ -20,6 +20,7 @@ import ( "github.com/arduino/arduino-cli/cli/output" "github.com/arduino/arduino-cli/commands" + "github.com/arduino/arduino-cli/i18n" rpc "github.com/arduino/arduino-cli/rpc/commands" "github.com/pkg/errors" "github.com/sirupsen/logrus" diff --git a/i18n/cmd/commands/root.go b/i18n/cmd/commands/root.go index 2b1c5418853..852f3a53688 100644 --- a/i18n/cmd/commands/root.go +++ b/i18n/cmd/commands/root.go @@ -2,6 +2,7 @@ package commands import ( "github.com/arduino/arduino-cli/i18n/cmd/commands/catalog" + "github.com/arduino/arduino-cli/i18n/cmd/commands/transifex" "github.com/spf13/cobra" ) @@ -12,6 +13,7 @@ var i18nCommand = &cobra.Command{ func init() { i18nCommand.AddCommand(catalog.Command) + i18nCommand.AddCommand(transifex.Command) } // Execute executes the i18n command diff --git a/i18n/cmd/commands/transifex/pull_transifex.go b/i18n/cmd/commands/transifex/pull_transifex.go new file mode 100644 index 00000000000..20916fdcb4c --- /dev/null +++ b/i18n/cmd/commands/transifex/pull_transifex.go @@ -0,0 +1,69 @@ +package transifex + +import ( + "fmt" + "io/ioutil" + "net/http" + "os" + "path" + + "github.com/spf13/cobra" +) + +var pullTransifexCommand = &cobra.Command{ + Use: "pull -l pt_BR [catalog folder]", + Short: "pulls the translation files from transifex", + Args: cobra.ExactArgs(1), + Run: pullCatalog, +} + +func pullCatalog(cmd *cobra.Command, args []string) { + folder := args[0] + + for _, lang := range languages { + + req, err := http.NewRequest( + "GET", + fmt.Sprintf( + "https://www.transifex.com/api/2/project/%s/resource/%s/translation/%s/?mode=reviewed&file=po", + project, resource, lang, + ), nil) + + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + req.SetBasicAuth("api", apiKey) + + resp, err := http.DefaultClient.Do(req) + + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + defer resp.Body.Close() + + b, err := ioutil.ReadAll(resp.Body) + + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + os.Remove(path.Join(folder, lang+".po")) + file, err := os.OpenFile(path.Join(folder, lang+".po"), os.O_CREATE|os.O_RDWR, 0644) + + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + _, err = file.Write(b) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + } +} diff --git a/i18n/cmd/commands/transifex/push_transifex.go b/i18n/cmd/commands/transifex/push_transifex.go new file mode 100644 index 00000000000..3097510cd15 --- /dev/null +++ b/i18n/cmd/commands/transifex/push_transifex.go @@ -0,0 +1,86 @@ +package transifex + +import ( + "bytes" + "fmt" + "io" + "mime/multipart" + "net/http" + "os" + "path" + "path/filepath" + + "github.com/spf13/cobra" +) + +var pushTransifexCommand = &cobra.Command{ + Use: "push -l pt_BR [catalog folder]", + Short: "pushes the translation files to transifex", + Args: cobra.ExactArgs(1), + Run: pushCatalog, +} + +func pushFile(folder, lang, url string) { + filename := path.Join(folder, lang+".po") + file, err := os.Open(filename) + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + defer file.Close() + + body := &bytes.Buffer{} + writer := multipart.NewWriter(body) + part, err := writer.CreateFormFile(lang, filepath.Base(filename)) + + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + _, err = io.Copy(part, file) + writer.WriteField("file_type", "po") + + req, err := http.NewRequest("PUT", url, body) + req.Header.Set("Content-Type", writer.FormDataContentType()) + + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + + req.SetBasicAuth("api", apiKey) + + resp, err := http.DefaultClient.Do(req) + + if err != nil { + fmt.Println(err.Error()) + os.Exit(1) + } + resp.Body.Close() +} + +func pushCatalog(cmd *cobra.Command, args []string) { + folder := args[0] + + pushFile( + folder, + "en", + fmt.Sprintf( + "https://www.transifex.com/api/2/project/%s/resource/%s/content/", + project, + resource, + ), + ) + + for _, lang := range languages { + pushFile( + folder, + lang, + fmt.Sprintf( + "https://www.transifex.com/api/2/project/%s/resource/%s/translation/%s/", + project, resource, lang, + ), + ) + } +} diff --git a/i18n/cmd/commands/transifex/transifex.go b/i18n/cmd/commands/transifex/transifex.go new file mode 100644 index 00000000000..b457593b76d --- /dev/null +++ b/i18n/cmd/commands/transifex/transifex.go @@ -0,0 +1,51 @@ +package transifex + +import ( + "fmt" + "os" + + "github.com/spf13/cobra" +) + +// Command is the transifex command +var Command = &cobra.Command{ + Use: "transifex", + Short: "transifex", + PersistentPreRun: preRun, +} + +var project string +var resource string +var apiKey string +var languages = []string{} + +func init() { + Command.AddCommand(pullTransifexCommand) + Command.AddCommand(pushTransifexCommand) + + Command.PersistentFlags().StringSliceVarP(&languages, "languages", "l", nil, "languages") + Command.MarkFlagRequired("languages") +} + +func preRun(cmd *cobra.Command, args []string) { + project = os.Getenv("TRANSIFEX_PROJECT") + resource = os.Getenv("TRANSIFEX_RESOURCE") + apiKey = os.Getenv("TRANSIFEX_RESOURCE") + + if project = os.Getenv("TRANSIFEX_PROJECT"); project == "" { + fmt.Println("missing TRANSIFEX_PROJECT environment variable") + os.Exit(1) + } + + if resource = os.Getenv("TRANSIFEX_RESOURCE"); resource == "" { + fmt.Println("missing TRANSIFEX_RESOURCE environment variable") + os.Exit(1) + } + + if apiKey = os.Getenv("TRANSIFEX_API_KEY"); apiKey == "" { + fmt.Println("missing TRANSIFEX_API_KEY environment variable") + os.Exit(1) + } + + return +} From ceb1e03b50aa802f518c0b2bc68c3d9cb3fdbb28 Mon Sep 17 00:00:00 2001 From: Henrique Date: Wed, 6 May 2020 01:37:30 -0300 Subject: [PATCH 16/49] remove unused import --- cli/instance/instance.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cli/instance/instance.go b/cli/instance/instance.go index 0f7d8fa4243..37c0d355323 100644 --- a/cli/instance/instance.go +++ b/cli/instance/instance.go @@ -20,7 +20,6 @@ import ( "github.com/arduino/arduino-cli/cli/output" "github.com/arduino/arduino-cli/commands" - "github.com/arduino/arduino-cli/i18n" rpc "github.com/arduino/arduino-cli/rpc/commands" "github.com/pkg/errors" "github.com/sirupsen/logrus" From dd4f3fb714c1fde30a9e258408a9c405b277eeb2 Mon Sep 17 00:00:00 2001 From: Henrique Date: Tue, 12 May 2020 23:18:25 -0300 Subject: [PATCH 17/49] dont generate new rice file if there are no translation changes --- i18n/embed-i18n.sh | 4 ++++ i18n/locale.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100755 i18n/embed-i18n.sh diff --git a/i18n/embed-i18n.sh b/i18n/embed-i18n.sh new file mode 100755 index 00000000000..ea74949e943 --- /dev/null +++ b/i18n/embed-i18n.sh @@ -0,0 +1,4 @@ +#!/bin/sh + +git add -N ./data +git diff --exit-code ./data || rice embed-go \ No newline at end of file diff --git a/i18n/locale.go b/i18n/locale.go index b212f23d068..fd890da9ca3 100644 --- a/i18n/locale.go +++ b/i18n/locale.go @@ -1,6 +1,6 @@ package i18n -//go:generate rice embed-go +//go:generate ./embed-i18n.sh import ( "sync" From fa054dd4bed00e2b556ff456761123ad529ac455 Mon Sep 17 00:00:00 2001 From: Henrique Date: Tue, 12 May 2020 23:21:10 -0300 Subject: [PATCH 18/49] add copyright headers --- i18n/cmd/ast/parser.go | 15 +++++++++++++++ i18n/cmd/commands/catalog/catalog.go | 15 +++++++++++++++ i18n/cmd/commands/catalog/generate_catalog.go | 15 +++++++++++++++ i18n/cmd/commands/catalog/update_catalog.go | 15 +++++++++++++++ i18n/cmd/commands/root.go | 15 +++++++++++++++ i18n/cmd/commands/transifex/pull_transifex.go | 15 +++++++++++++++ i18n/cmd/commands/transifex/push_transifex.go | 15 +++++++++++++++ i18n/cmd/commands/transifex/transifex.go | 15 +++++++++++++++ i18n/cmd/main.go | 15 +++++++++++++++ i18n/cmd/po/catalog.go | 15 +++++++++++++++ i18n/cmd/po/merge.go | 15 +++++++++++++++ i18n/cmd/po/parser.go | 15 +++++++++++++++ i18n/i18n.go | 15 +++++++++++++++ i18n/i18n_test.go | 15 +++++++++++++++ i18n/locale.go | 15 +++++++++++++++ 15 files changed, 225 insertions(+) diff --git a/i18n/cmd/ast/parser.go b/i18n/cmd/ast/parser.go index 08694d2ac9c..4ada7b56184 100644 --- a/i18n/cmd/ast/parser.go +++ b/i18n/cmd/ast/parser.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package ast import ( diff --git a/i18n/cmd/commands/catalog/catalog.go b/i18n/cmd/commands/catalog/catalog.go index 3e12e850494..f092d2d8293 100644 --- a/i18n/cmd/commands/catalog/catalog.go +++ b/i18n/cmd/commands/catalog/catalog.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package catalog import "github.com/spf13/cobra" diff --git a/i18n/cmd/commands/catalog/generate_catalog.go b/i18n/cmd/commands/catalog/generate_catalog.go index 197ebe16c2b..a71dabf2c73 100644 --- a/i18n/cmd/commands/catalog/generate_catalog.go +++ b/i18n/cmd/commands/catalog/generate_catalog.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package catalog import ( diff --git a/i18n/cmd/commands/catalog/update_catalog.go b/i18n/cmd/commands/catalog/update_catalog.go index 8b6f187b2a8..e2b886d30a3 100644 --- a/i18n/cmd/commands/catalog/update_catalog.go +++ b/i18n/cmd/commands/catalog/update_catalog.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package catalog import ( diff --git a/i18n/cmd/commands/root.go b/i18n/cmd/commands/root.go index 852f3a53688..e05403669c0 100644 --- a/i18n/cmd/commands/root.go +++ b/i18n/cmd/commands/root.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package commands import ( diff --git a/i18n/cmd/commands/transifex/pull_transifex.go b/i18n/cmd/commands/transifex/pull_transifex.go index 20916fdcb4c..c03ac009f21 100644 --- a/i18n/cmd/commands/transifex/pull_transifex.go +++ b/i18n/cmd/commands/transifex/pull_transifex.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package transifex import ( diff --git a/i18n/cmd/commands/transifex/push_transifex.go b/i18n/cmd/commands/transifex/push_transifex.go index 3097510cd15..774901ad448 100644 --- a/i18n/cmd/commands/transifex/push_transifex.go +++ b/i18n/cmd/commands/transifex/push_transifex.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package transifex import ( diff --git a/i18n/cmd/commands/transifex/transifex.go b/i18n/cmd/commands/transifex/transifex.go index b457593b76d..0c5b7ac8c99 100644 --- a/i18n/cmd/commands/transifex/transifex.go +++ b/i18n/cmd/commands/transifex/transifex.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package transifex import ( diff --git a/i18n/cmd/main.go b/i18n/cmd/main.go index bf418cdb438..69b1373251e 100644 --- a/i18n/cmd/main.go +++ b/i18n/cmd/main.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package main import ( diff --git a/i18n/cmd/po/catalog.go b/i18n/cmd/po/catalog.go index b4e91c800de..fd294022dfa 100644 --- a/i18n/cmd/po/catalog.go +++ b/i18n/cmd/po/catalog.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package po import ( diff --git a/i18n/cmd/po/merge.go b/i18n/cmd/po/merge.go index 7817eb0d872..c4a74b0d16f 100644 --- a/i18n/cmd/po/merge.go +++ b/i18n/cmd/po/merge.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package po // Merge merges two message catalogs, preserving only keys present in source diff --git a/i18n/cmd/po/parser.go b/i18n/cmd/po/parser.go index 8e102446ac7..a105b80cba2 100644 --- a/i18n/cmd/po/parser.go +++ b/i18n/cmd/po/parser.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package po import ( diff --git a/i18n/i18n.go b/i18n/i18n.go index b0ee23c4cc2..4980b508060 100644 --- a/i18n/i18n.go +++ b/i18n/i18n.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package i18n // Tr returns msg translated to the selected locale diff --git a/i18n/i18n_test.go b/i18n/i18n_test.go index 15fd99979cf..93cde6f2126 100644 --- a/i18n/i18n_test.go +++ b/i18n/i18n_test.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package i18n import ( diff --git a/i18n/locale.go b/i18n/locale.go index fd890da9ca3..869c7abacd2 100644 --- a/i18n/locale.go +++ b/i18n/locale.go @@ -1,3 +1,18 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + package i18n //go:generate ./embed-i18n.sh From 74a7971dc20c821aa25fa46f9b7717457647df5d Mon Sep 17 00:00:00 2001 From: Henrique Date: Tue, 12 May 2020 23:28:18 -0300 Subject: [PATCH 19/49] use 'tr' function call as indicator for translations --- i18n/cmd/ast/parser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/cmd/ast/parser.go b/i18n/cmd/ast/parser.go index 4ada7b56184..943f2ae2aa4 100644 --- a/i18n/cmd/ast/parser.go +++ b/i18n/cmd/ast/parser.go @@ -54,7 +54,7 @@ func doFile(fset *token.FileSet, file *ast.File, catalog *po.MessageCatalog) { return true } - if functionName(funcCall) != "i18n.Tr" { + if functionName(funcCall) != "i18n.Tr" && functionName(funcCall) != "tr" { return true } From 58799288a805e409ba792681b1077cc90a992359 Mon Sep 17 00:00:00 2001 From: Henrique Date: Tue, 12 May 2020 23:36:38 -0300 Subject: [PATCH 20/49] adding documentation to pull,push translations and adding new languages --- i18n/README.md | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/i18n/README.md b/i18n/README.md index 37dd333b6ad..417fc3cbdd8 100644 --- a/i18n/README.md +++ b/i18n/README.md @@ -17,4 +17,37 @@ The following command updates the locales present in the source code to reflect ```sh task i18n:update +``` + +## Syncing the catalog with transifex + +### Environment variables + +Set the following environment variables according to the project + +|Variable|Description| +|--------|-----------| +|TRANSIFEX_PROJECT|Name of the transifex project| +|TRANSIFEX_RESOURCE|Name of the transifex translation resource| +|TRANSIFEX_API_KEY|API Key to access the transifex project| + +### Push + +```sh +task i18n:push +``` + +### Pull + +```sh +task i18n:pull +``` + +## Adding a new language + +To add a new supported language add the locale string to the project's Taskfile.yml (comma separated list) + +e.g +``` +I18N_LANGS: "pt_BR,es,jp" ``` \ No newline at end of file From 76286340a02e655bcae8b57c897a8b9ead158e56 Mon Sep 17 00:00:00 2001 From: Henrique Date: Thu, 14 May 2020 02:33:08 -0300 Subject: [PATCH 21/49] push only the reference translation catalog --- Taskfile.yml | 2 +- i18n/cmd/commands/transifex/pull_transifex.go | 7 +++++++ i18n/cmd/commands/transifex/push_transifex.go | 13 +------------ i18n/cmd/commands/transifex/transifex.go | 4 ---- 4 files changed, 9 insertions(+), 17 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index fc9eadfa695..3616fb760f3 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -130,7 +130,7 @@ tasks: i18n:push: desc: Push i18n files to transifex cmds: - - go run ./i18n/cmd/main.go transifex push -l {{.I18N_LANGS}} ./i18n/data + - go run ./i18n/cmd/main.go transifex push ./i18n/data vars: # all modules of this project except for "legacy/..." module diff --git a/i18n/cmd/commands/transifex/pull_transifex.go b/i18n/cmd/commands/transifex/pull_transifex.go index c03ac009f21..e94755789cd 100644 --- a/i18n/cmd/commands/transifex/pull_transifex.go +++ b/i18n/cmd/commands/transifex/pull_transifex.go @@ -32,6 +32,13 @@ var pullTransifexCommand = &cobra.Command{ Run: pullCatalog, } +var languages = []string{} + +func init() { + pullTransifexCommand.Flags().StringSliceVarP(&languages, "languages", "l", nil, "languages") + pullTransifexCommand.MarkFlagRequired("languages") +} + func pullCatalog(cmd *cobra.Command, args []string) { folder := args[0] diff --git a/i18n/cmd/commands/transifex/push_transifex.go b/i18n/cmd/commands/transifex/push_transifex.go index 774901ad448..40a28a2bbb6 100644 --- a/i18n/cmd/commands/transifex/push_transifex.go +++ b/i18n/cmd/commands/transifex/push_transifex.go @@ -29,7 +29,7 @@ import ( ) var pushTransifexCommand = &cobra.Command{ - Use: "push -l pt_BR [catalog folder]", + Use: "push [catalog folder]", Short: "pushes the translation files to transifex", Args: cobra.ExactArgs(1), Run: pushCatalog, @@ -87,15 +87,4 @@ func pushCatalog(cmd *cobra.Command, args []string) { resource, ), ) - - for _, lang := range languages { - pushFile( - folder, - lang, - fmt.Sprintf( - "https://www.transifex.com/api/2/project/%s/resource/%s/translation/%s/", - project, resource, lang, - ), - ) - } } diff --git a/i18n/cmd/commands/transifex/transifex.go b/i18n/cmd/commands/transifex/transifex.go index 0c5b7ac8c99..63fb3750ba2 100644 --- a/i18n/cmd/commands/transifex/transifex.go +++ b/i18n/cmd/commands/transifex/transifex.go @@ -32,14 +32,10 @@ var Command = &cobra.Command{ var project string var resource string var apiKey string -var languages = []string{} func init() { Command.AddCommand(pullTransifexCommand) Command.AddCommand(pushTransifexCommand) - - Command.PersistentFlags().StringSliceVarP(&languages, "languages", "l", nil, "languages") - Command.MarkFlagRequired("languages") } func preRun(cmd *cobra.Command, args []string) { From e09185a94056c8b03e8aaba4adf44fb8ca972b16 Mon Sep 17 00:00:00 2001 From: Henrique Date: Thu, 14 May 2020 02:33:34 -0300 Subject: [PATCH 22/49] add check on PR for updated catalog not commited --- .github/workflows/i18n-pr-check.yaml | 33 ++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 .github/workflows/i18n-pr-check.yaml diff --git a/.github/workflows/i18n-pr-check.yaml b/.github/workflows/i18n-pr-check.yaml new file mode 100644 index 00000000000..9ddd7a7d535 --- /dev/null +++ b/.github/workflows/i18n-pr-check.yaml @@ -0,0 +1,33 @@ +name: i18n-pr-check + +on: + pull_request: + +jobs: + verify-messages-updated: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@master + + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: '1.14' + + - name: Install Go deps + run: | + go get github.com/GeertJohan/go.rice/rice + + - name: Install Taskfile + uses: Arduino/actions/setup-taskfile@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Run task i18n:update + run: task i18n:update + + - name: Check if translations were updated + run: | + git add -N ./i18n/data + git diff --exit-code ./i18n/data \ No newline at end of file From 4560261e28fd6099fe64d526fa419f760c19b99d Mon Sep 17 00:00:00 2001 From: Henrique Date: Thu, 14 May 2020 02:33:54 -0300 Subject: [PATCH 23/49] push message catalog to transifex --- .github/workflows/i18n-nightly-push.yaml | 30 ++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 .github/workflows/i18n-nightly-push.yaml diff --git a/.github/workflows/i18n-nightly-push.yaml b/.github/workflows/i18n-nightly-push.yaml new file mode 100644 index 00000000000..85e60fefadc --- /dev/null +++ b/.github/workflows/i18n-nightly-push.yaml @@ -0,0 +1,30 @@ +name: i18n-nightly-push + +on: + schedule: + # run every day at 1AM + - cron: '0 1 * * *' + +jobs: + push-to-transifex: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@master + + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: '1.14' + + - name: Install Taskfile + uses: Arduino/actions/setup-taskfile@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Run task i18n:push + run: task i18n:push + env: + TRANSIFEX_PROJECT: ${{ secrets.TRANSIFEX_PROJECT }} + TRANSIFEX_RESOURCE: ${{ secrets.TRANSIFEX_RESOURCE }} + TRANSIFEX_API_KEY: ${{ secrets.TRANSIFEX_API_KEY }} \ No newline at end of file From b29dd93ce0567b63ecfa9944637b76b0160ee88e Mon Sep 17 00:00:00 2001 From: Henrique Date: Thu, 14 May 2020 02:34:17 -0300 Subject: [PATCH 24/49] pull translations fro transifex weekly --- .github/workflows/i18n-weekly-pull.yaml | 41 +++++++++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 .github/workflows/i18n-weekly-pull.yaml diff --git a/.github/workflows/i18n-weekly-pull.yaml b/.github/workflows/i18n-weekly-pull.yaml new file mode 100644 index 00000000000..06fd5c84e36 --- /dev/null +++ b/.github/workflows/i18n-weekly-pull.yaml @@ -0,0 +1,41 @@ +name: i18n-weekly-pull + +on: + schedule: + # run every monday at 2AM + - cron: '0 2 * * 1' + +jobs: + pull-from-transifex: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@master + + - name: Install Go + uses: actions/setup-go@v2 + with: + go-version: '1.14' + + - name: Install Go deps + run: | + go get github.com/GeertJohan/go.rice/rice + + - name: Install Taskfile + uses: Arduino/actions/setup-taskfile@master + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Run task i18n:pull + run: task i18n:pull + env: + TRANSIFEX_PROJECT: ${{ secrets.TRANSIFEX_PROJECT }} + TRANSIFEX_RESOURCE: ${{ secrets.TRANSIFEX_RESOURCE }} + TRANSIFEX_API_KEY: ${{ secrets.TRANSIFEX_API_KEY }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v2 + with: + commit-message: Updated translation files + title: Updated translation files + branch: i18n/translations-update \ No newline at end of file From 94c6afd2658c8338c573766144998f337e5ca966 Mon Sep 17 00:00:00 2001 From: Henrique Date: Thu, 14 May 2020 16:52:46 -0300 Subject: [PATCH 25/49] get locale identifier from diferent OSes --- cli/cli.go | 6 +++--- i18n/detect.go | 35 +++++++++++++++++++++++++++++++ i18n/detect_darwin.go | 37 +++++++++++++++++++++++++++++++++ i18n/detect_linux.go | 20 ++++++++++++++++++ i18n/detect_windows.go | 47 ++++++++++++++++++++++++++++++++++++++++++ i18n/i18n.go | 25 ++++++++++++++++++++++ i18n/locale.go | 23 +++++++++++++++++---- 7 files changed, 186 insertions(+), 7 deletions(-) create mode 100644 i18n/detect.go create mode 100644 i18n/detect_darwin.go create mode 100644 i18n/detect_linux.go create mode 100644 i18n/detect_windows.go diff --git a/cli/cli.go b/cli/cli.go index 59430a9323b..68209743b2b 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -169,9 +169,6 @@ func preRun(cmd *cobra.Command, args []string) { configuration.Init(configPath) configFile := viper.ConfigFileUsed() - // initialize locale - i18n.SetLocale(viper.GetString("locale")) - // initialize inventory inventory.Init(viper.GetString("directories.Data")) @@ -258,4 +255,7 @@ func preRun(cmd *cobra.Command, args []string) { os.Exit(errorcodes.ErrBadCall) }) } + + // initialize locale + i18n.Init() } diff --git a/i18n/detect.go b/i18n/detect.go new file mode 100644 index 00000000000..f35d4f1b94e --- /dev/null +++ b/i18n/detect.go @@ -0,0 +1,35 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package i18n + +import ( + "os" + "strings" +) + +func getLocaleIdentifierFromOS() string { + return getLocaleIdentifier() +} + +func getLocaleIdentifierFromEnv() string { + locale := os.Getenv("LC_ALL") + + if locale == "" { + locale = os.Getenv("LANG") + } + + return strings.Split(locale, ".")[0] +} diff --git a/i18n/detect_darwin.go b/i18n/detect_darwin.go new file mode 100644 index 00000000000..00503ba0ae8 --- /dev/null +++ b/i18n/detect_darwin.go @@ -0,0 +1,37 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package i18n + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Foundation +#import + +const char* getLocaleIdentifier() { + NSString *cs = [[NSLocale currentLocale] localeIdentifier]; + const char *cstr = [cs UTF8String]; + return cstr; +} + +*/ +import "C" + +func getLocaleIdentifier() string { + if envLocale := getLocaleIdentifierFromEnv(); envLocale != "" { + return envLocale + } + return C.GoString(C.getLocaleIdentifier()) +} diff --git a/i18n/detect_linux.go b/i18n/detect_linux.go new file mode 100644 index 00000000000..759509c5abe --- /dev/null +++ b/i18n/detect_linux.go @@ -0,0 +1,20 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package i18n + +func getLocaleIdentifier() string { + return getLocaleIdentifierFromEnv() +} diff --git a/i18n/detect_windows.go b/i18n/detect_windows.go new file mode 100644 index 00000000000..2210bfa2553 --- /dev/null +++ b/i18n/detect_windows.go @@ -0,0 +1,47 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package i18n + +import ( + "fmt" + "strings" + "syscall" + "unsafe" +) + +func getLocaleIdentifier() string { + defer func() { + if r := recover(); r != nil { + fmt.Println("failed to get windows user locale", r) + } + }() + + dll := syscall.MustLoadDLL("kernel32") + defer dll.Release() + proc := dll.MustFindProc("GetUserDefaultLocaleName") + + localeNameMaxLen := 85 + buffer := make([]uint16, localeNameMaxLen) + len, _, err := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(localeNameMaxLen)) + + if len == 0 { + panic(err) + } + + locale := syscall.UTF16ToString(buffer) + + return strings.ReplaceAll(locale, "-", "_") +} diff --git a/i18n/i18n.go b/i18n/i18n.go index 4980b508060..15ecd70a93d 100644 --- a/i18n/i18n.go +++ b/i18n/i18n.go @@ -15,6 +15,31 @@ package i18n +import ( + "github.com/spf13/viper" +) + +// Init initializes the i18n module, setting the locale according to this order of preference: +// 1. Configuration set in arduino-cli.yaml +// 2. OS Locale +// 3. en (default) +func Init() { + + if configLocale := viper.GetString("locale"); configLocale != "" { + if setLocale(configLocale) { + return + } + } + + if osLocale := getLocaleIdentifierFromOS(); osLocale != "" { + if setLocale(osLocale) { + return + } + } + + setLocale("en") +} + // Tr returns msg translated to the selected locale // the msg argument must be a literal string func Tr(msg string, args ...interface{}) string { diff --git a/i18n/locale.go b/i18n/locale.go index 869c7abacd2..53bbd646e76 100644 --- a/i18n/locale.go +++ b/i18n/locale.go @@ -18,6 +18,7 @@ package i18n //go:generate ./embed-i18n.sh import ( + "strings" "sync" rice "github.com/GeertJohan/go.rice" @@ -27,21 +28,35 @@ import ( var ( loadOnce sync.Once po *gotext.Po + box *rice.Box ) func init() { po = new(gotext.Po) } -// SetLocale sets the locate used for i18n -func SetLocale(locale string) { - box := rice.MustFindBox("./data") +func setLocale(locale string) bool { + loadOnce.Do(func() { + box = rice.MustFindBox("./data") + }) + poFile, err := box.Bytes(locale + ".po") if err != nil { - poFile = box.MustBytes("en.po") + parts := strings.Split(locale, "_") + if len(parts) > 1 { + locale = parts[0] + poFile, err = box.Bytes(locale + ".po") + + if err != nil { + return false + } + } else { + return false + } } po = new(gotext.Po) po.Parse(poFile) + return true } From 4d076f914a6849137f35cba0d08182034fa0ba3b Mon Sep 17 00:00:00 2001 From: Henrique Date: Thu, 14 May 2020 16:52:46 -0300 Subject: [PATCH 26/49] get locale identifier from diferent OSes --- Taskfile.yml | 7 +++++++ i18n/embed-i18n.sh | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/Taskfile.yml b/Taskfile.yml index 3616fb760f3..fdc46e17946 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -102,6 +102,7 @@ tasks: - test -z $(go fmt {{ default .DEFAULT_TARGETS .TARGETS }}) - go vet {{ default .DEFAULT_TARGETS .TARGETS }} - "'{{.GOLINTBIN}}' {{.GOLINTFLAGS}} {{ default .DEFAULT_TARGETS .TARGETS }}" + - task: i18n:check check-legacy: desc: Check fmt and lint for the `legacy` package @@ -132,6 +133,12 @@ tasks: cmds: - go run ./i18n/cmd/main.go transifex push ./i18n/data + i18n:check: + desc: Check if the i18n message catalog was updated + cmds: + - task: i18n:update + - git add -N ./i18n/data + - git diff --exit-code ./i18n/data &> /dev/null || echo "The i18n message catalog was updated, commit the changes before proceeding" vars: # all modules of this project except for "legacy/..." module DEFAULT_TARGETS: diff --git a/i18n/embed-i18n.sh b/i18n/embed-i18n.sh index ea74949e943..02194448f73 100755 --- a/i18n/embed-i18n.sh +++ b/i18n/embed-i18n.sh @@ -1,4 +1,4 @@ #!/bin/sh git add -N ./data -git diff --exit-code ./data || rice embed-go \ No newline at end of file +git diff --exit-code ./data &> /dev/null || rice embed-go \ No newline at end of file From ed9b5233e452f03783bb9c6a6f4407c532f13f42 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 13:39:13 -0300 Subject: [PATCH 27/49] match locale algo --- i18n/i18n.go | 8 ++++++-- i18n/locale.go | 54 ++++++++++++++++++++++++++++++++++++-------------- 2 files changed, 45 insertions(+), 17 deletions(-) diff --git a/i18n/i18n.go b/i18n/i18n.go index 15ecd70a93d..7e60ffd17bc 100644 --- a/i18n/i18n.go +++ b/i18n/i18n.go @@ -24,15 +24,19 @@ import ( // 2. OS Locale // 3. en (default) func Init() { + initRiceBox() + locales := supportedLocales() if configLocale := viper.GetString("locale"); configLocale != "" { - if setLocale(configLocale) { + if locale := findMatchingLocale(configLocale, locales); locale != "" { + setLocale(locale) return } } if osLocale := getLocaleIdentifierFromOS(); osLocale != "" { - if setLocale(osLocale) { + if locale := findMatchingLocale(osLocale, locales); locale != "" { + setLocale(locale) return } } diff --git a/i18n/locale.go b/i18n/locale.go index 53bbd646e76..ebc1991e283 100644 --- a/i18n/locale.go +++ b/i18n/locale.go @@ -18,6 +18,8 @@ package i18n //go:generate ./embed-i18n.sh import ( + "os" + "path/filepath" "strings" "sync" @@ -35,28 +37,50 @@ func init() { po = new(gotext.Po) } -func setLocale(locale string) bool { - loadOnce.Do(func() { - box = rice.MustFindBox("./data") +func initRiceBox() { + box = rice.MustFindBox("./data") +} + +func supportedLocales() []string { + var locales []string + box.Walk("", func(path string, info os.FileInfo, err error) error { + if filepath.Ext(path) == ".po" { + locales = append(locales, strings.TrimSuffix(path, ".po")) + } + return nil }) + return locales +} + +func findMatchingLanguage(language string, supportedLocales []string) string { + var matchingLocales []string + for _, supportedLocale := range supportedLocales { + if strings.HasPrefix(supportedLocale, language) { + matchingLocales = append(matchingLocales, supportedLocale) + } + } - poFile, err := box.Bytes(locale + ".po") + if len(matchingLocales) == 1 { + return matchingLocales[0] + } - if err != nil { - parts := strings.Split(locale, "_") - if len(parts) > 1 { - locale = parts[0] - poFile, err = box.Bytes(locale + ".po") + return "" +} - if err != nil { - return false - } - } else { - return false +func findMatchingLocale(locale string, supportedLocales []string) string { + for _, suportedLocale := range supportedLocales { + if locale == suportedLocale { + return suportedLocale } } + parts := strings.Split(locale, "_") + + return findMatchingLanguage(parts[0], supportedLocales) +} + +func setLocale(locale string) { + poFile := box.MustBytes(locale + ".po") po = new(gotext.Po) po.Parse(poFile) - return true } From 38b78aac6ee3055d6caed978494ea152ac63f574 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 13:39:27 -0300 Subject: [PATCH 28/49] add locale match test --- i18n/locale_test.go | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) create mode 100644 i18n/locale_test.go diff --git a/i18n/locale_test.go b/i18n/locale_test.go new file mode 100644 index 00000000000..6212258e8f8 --- /dev/null +++ b/i18n/locale_test.go @@ -0,0 +1,38 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package i18n + +import ( + "testing" + + "github.com/stretchr/testify/require" +) + +func TestLocaleMatch(t *testing.T) { + supportedLocales := []string{ + "en", + "pt_BR", + "it_IT", + "es_CO", + "es_ES", + } + + require.Equal(t, "pt_BR", findMatchingLocale("pt", supportedLocales), "Language match") + require.Equal(t, "pt_BR", findMatchingLocale("pt_BR", supportedLocales), "Exact match") + require.Equal(t, "pt_BR", findMatchingLocale("pt_PT", supportedLocales), "Language match with country") + require.Equal(t, "", findMatchingLocale("es", supportedLocales), "Multiple languages match") + require.Equal(t, "", findMatchingLocale("zn_CH", supportedLocales), "Not supported") +} From c977f8c3a07472ba445847ec4fc0a73dbe37e3b1 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 15:59:36 -0300 Subject: [PATCH 29/49] preserve LF in translation string unchanged --- i18n/cmd/po/parser.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/cmd/po/parser.go b/i18n/cmd/po/parser.go index a105b80cba2..4d2772a9e12 100644 --- a/i18n/cmd/po/parser.go +++ b/i18n/cmd/po/parser.go @@ -114,7 +114,7 @@ func mustUnquote(line string) string { fmt.Println(err.Error()) os.Exit(1) } - return v + return strings.ReplaceAll(v, "\n", "\\n") } func fileExists(filename string) bool { From 2d4b2881518c0cbddad55434e39317eca3238634 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 16:08:58 -0300 Subject: [PATCH 30/49] init config before executing command --- cli/cli.go | 47 ------------------------------- configuration/configuration.go | 51 ++++++++++++++++++++++++++++++++++ main.go | 2 ++ 3 files changed, 53 insertions(+), 47 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index 68209743b2b..34caa87cdf7 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -16,10 +16,8 @@ package cli import ( - "fmt" "io/ioutil" "os" - "path/filepath" "strings" "github.com/arduino/arduino-cli/cli/board" @@ -121,52 +119,7 @@ func parseFormatString(arg string) (feedback.OutputFormat, bool) { return f, found } -// This function is here to replicate the old logic looking for a config -// file in the parent tree of the CWD, aka "project config". -// Please -func searchConfigTree(cwd string) string { - // go back up to root and search for the config file - for { - if _, err := os.Stat(filepath.Join(cwd, "arduino-cli.yaml")); err == nil { - // config file found - return cwd - } else if os.IsNotExist(err) { - // no config file found - next := filepath.Dir(cwd) - if next == cwd { - return "" - } - cwd = next - } else { - // some error we can't handle happened - return "" - } - } -} - func preRun(cmd *cobra.Command, args []string) { - // - // Prepare the configuration system - // - configPath := "" - - // get cwd, if something is wrong don't do anything and let - // configuration init proceed - if cwd, err := os.Getwd(); err == nil { - configPath = searchConfigTree(cwd) - } - - // override the config path if --config-file was passed - if fi, err := os.Stat(configFile); err == nil { - if fi.IsDir() { - configPath = configFile - } else { - configPath = filepath.Dir(configFile) - } - } - - // initialize the config system - configuration.Init(configPath) configFile := viper.ConfigFileUsed() // initialize inventory diff --git a/configuration/configuration.go b/configuration/configuration.go index 5dd4218baea..3c907477192 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -180,3 +180,54 @@ func IsBundledInDesktopIDE() bool { return true } + +// FindConfigFile returns the config file path using the argument '--config-file' if specified or via the current working dir +func FindConfigFile() string { + + configFile := "" + for i, arg := range os.Args { + // 0 --config-file ss + if arg == "--config-file" { + if len(os.Args) > i+1 { + configFile = os.Args[i+1] + } + } + } + + if configFile != "" { + if fi, err := os.Stat(configFile); err == nil { + if fi.IsDir() { + return configFile + } + return filepath.Dir(configFile) + } + } + + return searchCwdForConfig() +} + +func searchCwdForConfig() string { + cwd, err := os.Getwd() + + if err != nil { + return "" + } + + // go back up to root and search for the config file + for { + if _, err := os.Stat(filepath.Join(cwd, "arduino-cli.yaml")); err == nil { + // config file found + return cwd + } else if os.IsNotExist(err) { + // no config file found + next := filepath.Dir(cwd) + if next == cwd { + return "" + } + cwd = next + } else { + // some error we can't handle happened + return "" + } + } +} diff --git a/main.go b/main.go index 4ab55ba9d8e..f2032dff996 100644 --- a/main.go +++ b/main.go @@ -20,9 +20,11 @@ import ( "github.com/arduino/arduino-cli/cli" "github.com/arduino/arduino-cli/cli/errorcodes" + "github.com/arduino/arduino-cli/configuration" ) func main() { + configuration.Init(configuration.FindConfigFile()) if err := cli.ArduinoCli.Execute(); err != nil { os.Exit(errorcodes.ErrGeneric) } From 749192db0ac565959fe677927d8ada923a4f27af Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 16:14:08 -0300 Subject: [PATCH 31/49] create arduino cmd dynamically --- cli/cli.go | 24 +++++++++++------------- main.go | 5 ++++- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/cli/cli.go b/cli/cli.go index 34caa87cdf7..71824265f46 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -16,6 +16,7 @@ package cli import ( + "fmt" "io/ioutil" "os" "strings" @@ -36,8 +37,6 @@ import ( "github.com/arduino/arduino-cli/cli/sketch" "github.com/arduino/arduino-cli/cli/upload" "github.com/arduino/arduino-cli/cli/version" - "github.com/arduino/arduino-cli/configuration" - "github.com/arduino/arduino-cli/i18n" "github.com/arduino/arduino-cli/inventory" "github.com/mattn/go-colorable" "github.com/rifflock/lfshook" @@ -47,8 +46,15 @@ import ( ) var ( + verbose bool + outputFormat string + configFile string +) + +// NewCommand creates a new ArduinoCli command root +func NewCommand() *cobra.Command { // ArduinoCli is the root command - ArduinoCli = &cobra.Command{ + arduinoCli := &cobra.Command{ Use: "arduino-cli", Short: "Arduino CLI.", Long: "Arduino Command Line Interface (arduino-cli).", @@ -56,14 +62,9 @@ var ( PersistentPreRun: preRun, } - verbose bool - outputFormat string - configFile string -) + createCliCommandTree(arduinoCli) -// Init the cobra root command -func init() { - createCliCommandTree(ArduinoCli) + return arduinoCli } // this is here only for testing @@ -208,7 +209,4 @@ func preRun(cmd *cobra.Command, args []string) { os.Exit(errorcodes.ErrBadCall) }) } - - // initialize locale - i18n.Init() } diff --git a/main.go b/main.go index f2032dff996..d4a43cf81c8 100644 --- a/main.go +++ b/main.go @@ -21,11 +21,14 @@ import ( "github.com/arduino/arduino-cli/cli" "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/configuration" + "github.com/arduino/arduino-cli/i18n" ) func main() { configuration.Init(configuration.FindConfigFile()) - if err := cli.ArduinoCli.Execute(); err != nil { + i18n.Init() + arduinoCmd := cli.NewCommand() + if err := arduinoCmd.Execute(); err != nil { os.Exit(errorcodes.ErrGeneric) } } From 968931d15d78a28769c4322e8c7a4b4ad6573ca8 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 16:34:49 -0300 Subject: [PATCH 32/49] make all command init dynamically --- cli/board/board.go | 2 +- cli/board/details.go | 3 ++- cli/board/listall.go | 25 ++++++++++++++----------- cli/config/config.go | 2 +- cli/config/dump.go | 17 ++++++++++------- 5 files changed, 28 insertions(+), 21 deletions(-) diff --git a/cli/board/board.go b/cli/board/board.go index 613130a28b7..29ab85b4243 100644 --- a/cli/board/board.go +++ b/cli/board/board.go @@ -36,7 +36,7 @@ func NewCommand() *cobra.Command { boardCommand.AddCommand(initAttachCommand()) boardCommand.AddCommand(initDetailsCommand()) boardCommand.AddCommand(initListCommand()) - boardCommand.AddCommand(listAllCommand) + boardCommand.AddCommand(initListAllCommand()) return boardCommand } diff --git a/cli/board/details.go b/cli/board/details.go index 1b3d4ebe00a..56616f457ff 100644 --- a/cli/board/details.go +++ b/cli/board/details.go @@ -18,6 +18,8 @@ package board import ( "context" "fmt" + "os" + "github.com/arduino/arduino-cli/cli/errorcodes" "github.com/arduino/arduino-cli/cli/feedback" "github.com/arduino/arduino-cli/cli/instance" @@ -26,7 +28,6 @@ import ( "github.com/arduino/arduino-cli/table" "github.com/fatih/color" "github.com/spf13/cobra" - "os" ) var showFullDetails bool diff --git a/cli/board/listall.go b/cli/board/listall.go index d2e2c03eef0..0598b5dc5fd 100644 --- a/cli/board/listall.go +++ b/cli/board/listall.go @@ -29,17 +29,20 @@ import ( "github.com/spf13/cobra" ) -var listAllCommand = &cobra.Command{ - Use: "listall [boardname]", - Short: "List all known boards and their corresponding FQBN.", - Long: "" + - "List all boards that have the support platform installed. You can search\n" + - "for a specific board if you specify the board name", - Example: "" + - " " + os.Args[0] + " board listall\n" + - " " + os.Args[0] + " board listall zero", - Args: cobra.ArbitraryArgs, - Run: runListAllCommand, +func initListAllCommand() *cobra.Command { + var listAllCommand = &cobra.Command{ + Use: "listall [boardname]", + Short: "List all known boards and their corresponding FQBN.", + Long: "" + + "List all boards that have the support platform installed. You can search\n" + + "for a specific board if you specify the board name", + Example: "" + + " " + os.Args[0] + " board listall\n" + + " " + os.Args[0] + " board listall zero", + Args: cobra.ArbitraryArgs, + Run: runListAllCommand, + } + return listAllCommand } // runListAllCommand list all installed boards diff --git a/cli/config/config.go b/cli/config/config.go index a7463494664..c382532df8f 100644 --- a/cli/config/config.go +++ b/cli/config/config.go @@ -29,7 +29,7 @@ func NewCommand() *cobra.Command { Example: " " + os.Args[0] + " config init", } - configCommand.AddCommand(dumpCmd) + configCommand.AddCommand(initDumpCmd()) configCommand.AddCommand(initInitCommand()) return configCommand diff --git a/cli/config/dump.go b/cli/config/dump.go index d449790c5cb..c384a8d48a7 100644 --- a/cli/config/dump.go +++ b/cli/config/dump.go @@ -25,13 +25,16 @@ import ( "gopkg.in/yaml.v2" ) -var dumpCmd = &cobra.Command{ - Use: "dump", - Short: "Prints the current configuration", - Long: "Prints the current configuration.", - Example: " " + os.Args[0] + " config dump", - Args: cobra.NoArgs, - Run: runDumpCommand, +func initDumpCmd() *cobra.Command { + var dumpCmd = &cobra.Command{ + Use: "dump", + Short: "Prints the current configuration", + Long: "Prints the current configuration.", + Example: " " + os.Args[0] + " config dump", + Args: cobra.NoArgs, + Run: runDumpCommand, + } + return dumpCmd } // output from this command requires special formatting, let's create a dedicated From e4d201daaa0e997b941b742b177f04f1314f83cf Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 16:48:24 -0300 Subject: [PATCH 33/49] save all message occurrences in catalog --- i18n/cmd/po/catalog.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/i18n/cmd/po/catalog.go b/i18n/cmd/po/catalog.go index fd294022dfa..61322e93194 100644 --- a/i18n/cmd/po/catalog.go +++ b/i18n/cmd/po/catalog.go @@ -46,7 +46,7 @@ func (catalog *MessageCatalog) Add(id, value string, comment []string) { } if len(comment) != 0 { - catalog.Messages[id].Comments = comment + catalog.Messages[id].Comments = append(catalog.Messages[id].Comments, comment...) } } From cba0cf67387393dfe5af367e8fd584830f496be3 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 19:20:56 -0300 Subject: [PATCH 34/49] add translatable cli usage template --- cli/cli.go | 5 +++++ cli/usage.go | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 63 insertions(+) create mode 100644 cli/usage.go diff --git a/cli/cli.go b/cli/cli.go index 71824265f46..44504de44ed 100644 --- a/cli/cli.go +++ b/cli/cli.go @@ -37,6 +37,7 @@ import ( "github.com/arduino/arduino-cli/cli/sketch" "github.com/arduino/arduino-cli/cli/upload" "github.com/arduino/arduino-cli/cli/version" + "github.com/arduino/arduino-cli/i18n" "github.com/arduino/arduino-cli/inventory" "github.com/mattn/go-colorable" "github.com/rifflock/lfshook" @@ -53,6 +54,8 @@ var ( // NewCommand creates a new ArduinoCli command root func NewCommand() *cobra.Command { + cobra.AddTemplateFunc("tr", i18n.Tr) + // ArduinoCli is the root command arduinoCli := &cobra.Command{ Use: "arduino-cli", @@ -62,6 +65,8 @@ func NewCommand() *cobra.Command { PersistentPreRun: preRun, } + arduinoCli.SetUsageTemplate(usageTemplate) + createCliCommandTree(arduinoCli) return arduinoCli diff --git a/cli/usage.go b/cli/usage.go new file mode 100644 index 00000000000..6750e546742 --- /dev/null +++ b/cli/usage.go @@ -0,0 +1,58 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package cli + +import ( + "github.com/arduino/arduino-cli/i18n" +) + +// Declare ids used in usage +var ( + tr = i18n.Tr + _ = tr("Usage:") + _ = tr("Aliases:") + _ = tr("Examples:") + _ = tr("Available Commands:") + _ = tr("Flags:") + _ = tr("Global Flags:") + _ = tr("Additional help topics:") + _ = tr("Use %s for more information about a command.") +) + +const usageTemplate = `{{tr "Usage:"}}{{if .Runnable}} + {{.UseLine}}{{end}}{{if .HasAvailableSubCommands}} + {{.CommandPath}} [command]{{end}}{{if gt (len .Aliases) 0}} + +{{tr "Aliases:"}} + {{.NameAndAliases}}{{end}}{{if .HasExample}} + +{{tr "Examples:"}} +{{.Example}}{{end}}{{if .HasAvailableSubCommands}} + +{{tr "Available Commands:"}}{{range .Commands}}{{if (or .IsAvailableCommand (eq .Name "help"))}} + {{rpad .Name .NamePadding }} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableLocalFlags}} + +{{tr "Flags:"}} +{{.LocalFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasAvailableInheritedFlags}} + +{{tr "Global Flags:"}} +{{.InheritedFlags.FlagUsages | trimTrailingWhitespaces}}{{end}}{{if .HasHelpSubCommands}} + +{{tr "Additional help topics:"}}{{range .Commands}}{{if .IsAdditionalHelpTopicCommand}} + {{rpad .CommandPath .CommandPathPadding}} {{.Short}}{{end}}{{end}}{{end}}{{if .HasAvailableSubCommands}} + +{{tr "Use %s for more information about a command." (printf "%s %s" .CommandPath "[command] --help" | printf "%q")}}{{end}} +` From 56a0642d574fcb2456b7f6a029251b137f703570 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 20:56:09 -0300 Subject: [PATCH 35/49] add messages for cli usage template --- i18n/data/en.po | 32 ++++++++++++++++++++++++++++++++ i18n/data/pt_BR.po | 32 ++++++++++++++++++++++++++++++++ i18n/rice-box.go | 14 +++++++------- 3 files changed, 71 insertions(+), 7 deletions(-) diff --git a/i18n/data/en.po b/i18n/data/en.po index 3af2658d218..3d0f64e0456 100644 --- a/i18n/data/en.po +++ b/i18n/data/en.po @@ -1,3 +1,35 @@ msgid "" msgstr "" +#: ./cli/usage.go:31 +msgid "Additional help topics:" +msgstr "Additional help topics:" + +#: ./cli/usage.go:26 +msgid "Aliases:" +msgstr "Aliases:" + +#: ./cli/usage.go:28 +msgid "Available Commands:" +msgstr "Available Commands:" + +#: ./cli/usage.go:27 +msgid "Examples:" +msgstr "Examples:" + +#: ./cli/usage.go:29 +msgid "Flags:" +msgstr "Flags:" + +#: ./cli/usage.go:30 +msgid "Global Flags:" +msgstr "Global Flags:" + +#: ./cli/usage.go:25 +msgid "Usage:" +msgstr "Usage:" + +#: ./cli/usage.go:32 +msgid "Use %s for more information about a command." +msgstr "Use %s for more information about a command." + diff --git a/i18n/data/pt_BR.po b/i18n/data/pt_BR.po index 3af2658d218..410d4b6f324 100644 --- a/i18n/data/pt_BR.po +++ b/i18n/data/pt_BR.po @@ -1,3 +1,35 @@ msgid "" msgstr "" +#: ./cli/usage.go:31 +msgid "Additional help topics:" +msgstr "" + +#: ./cli/usage.go:26 +msgid "Aliases:" +msgstr "" + +#: ./cli/usage.go:28 +msgid "Available Commands:" +msgstr "" + +#: ./cli/usage.go:27 +msgid "Examples:" +msgstr "" + +#: ./cli/usage.go:29 +msgid "Flags:" +msgstr "" + +#: ./cli/usage.go:30 +msgid "Global Flags:" +msgstr "" + +#: ./cli/usage.go:25 +msgid "Usage:" +msgstr "" + +#: ./cli/usage.go:32 +msgid "Use %s for more information about a command." +msgstr "" + diff --git a/i18n/rice-box.go b/i18n/rice-box.go index f015a759077..a44d7e125c4 100644 --- a/i18n/rice-box.go +++ b/i18n/rice-box.go @@ -11,27 +11,27 @@ func init() { // define files file2 := &embedded.EmbeddedFile{ Filename: ".gitkeep", - FileModTime: time.Unix(1587752852, 0), + FileModTime: time.Unix(1589335267, 0), Content: string(""), } file3 := &embedded.EmbeddedFile{ Filename: "en.po", - FileModTime: time.Unix(1587758440, 0), + FileModTime: time.Unix(1589846460, 0), - Content: string("msgid \"\"\nmsgstr \"\"\n\n"), + Content: string("msgid \"\"\nmsgstr \"\"\n\n#: ./cli/usage.go:31\nmsgid \"Additional help topics:\"\nmsgstr \"Additional help topics:\"\n\n#: ./cli/usage.go:26\nmsgid \"Aliases:\"\nmsgstr \"Aliases:\"\n\n#: ./cli/usage.go:28\nmsgid \"Available Commands:\"\nmsgstr \"Available Commands:\"\n\n#: ./cli/usage.go:27\nmsgid \"Examples:\"\nmsgstr \"Examples:\"\n\n#: ./cli/usage.go:29\nmsgid \"Flags:\"\nmsgstr \"Flags:\"\n\n#: ./cli/usage.go:30\nmsgid \"Global Flags:\"\nmsgstr \"Global Flags:\"\n\n#: ./cli/usage.go:25\nmsgid \"Usage:\"\nmsgstr \"Usage:\"\n\n#: ./cli/usage.go:32\nmsgid \"Use %s for more information about a command.\"\nmsgstr \"Use %s for more information about a command.\"\n\n"), } file4 := &embedded.EmbeddedFile{ Filename: "pt_BR.po", - FileModTime: time.Unix(1587758441, 0), + FileModTime: time.Unix(1589846461, 0), - Content: string("msgid \"\"\nmsgstr \"\"\n\n"), + Content: string("msgid \"\"\nmsgstr \"\"\n\n#: ./cli/usage.go:31\nmsgid \"Additional help topics:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:26\nmsgid \"Aliases:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:28\nmsgid \"Available Commands:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:27\nmsgid \"Examples:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:29\nmsgid \"Flags:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:30\nmsgid \"Global Flags:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:25\nmsgid \"Usage:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:32\nmsgid \"Use %s for more information about a command.\"\nmsgstr \"\"\n\n"), } // define dirs dir1 := &embedded.EmbeddedDir{ Filename: "", - DirModTime: time.Unix(1587758441, 0), + DirModTime: time.Unix(1589846461, 0), ChildFiles: []*embedded.EmbeddedFile{ file2, // ".gitkeep" file3, // "en.po" @@ -46,7 +46,7 @@ func init() { // register embeddedBox embedded.RegisterEmbeddedBox(`./data`, &embedded.EmbeddedBox{ Name: `./data`, - Time: time.Unix(1587758441, 0), + Time: time.Unix(1589846461, 0), Dirs: map[string]*embedded.EmbeddedDir{ "": dir1, }, From 46af5e07888e25a04959e224adf59c20fac37159 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 20:58:09 -0300 Subject: [PATCH 36/49] remove standalone i18n message check --- .github/workflows/i18n-pr-check.yaml | 33 ---------------------------- 1 file changed, 33 deletions(-) delete mode 100644 .github/workflows/i18n-pr-check.yaml diff --git a/.github/workflows/i18n-pr-check.yaml b/.github/workflows/i18n-pr-check.yaml deleted file mode 100644 index 9ddd7a7d535..00000000000 --- a/.github/workflows/i18n-pr-check.yaml +++ /dev/null @@ -1,33 +0,0 @@ -name: i18n-pr-check - -on: - pull_request: - -jobs: - verify-messages-updated: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@master - - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: '1.14' - - - name: Install Go deps - run: | - go get github.com/GeertJohan/go.rice/rice - - - name: Install Taskfile - uses: Arduino/actions/setup-taskfile@master - with: - repo-token: ${{ secrets.GITHUB_TOKEN }} - - - name: Run task i18n:update - run: task i18n:update - - - name: Check if translations were updated - run: | - git add -N ./i18n/data - git diff --exit-code ./i18n/data \ No newline at end of file From ba1af89d665a83bc214950b0ac6bbcdba5f98779 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 21:25:46 -0300 Subject: [PATCH 37/49] add more i18n tests --- i18n/i18n_test.go | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/i18n/i18n_test.go b/i18n/i18n_test.go index 93cde6f2126..207673fb85b 100644 --- a/i18n/i18n_test.go +++ b/i18n/i18n_test.go @@ -16,7 +16,9 @@ package i18n import ( + "bytes" "testing" + "text/template" "github.com/leonelquinteros/gotext" "github.com/stretchr/testify/require" @@ -49,3 +51,47 @@ func TestTranslationWithVariables(t *testing.T) { require.Equal(t, "test-key", Tr("test-key")) require.Equal(t, "test-key-translated message", Tr("test-key-ok %s", "message")) } + +func TestTranslationInTemplate(t *testing.T) { + setPo(` + msgid "test-key" + msgstr "test-key-translated %s" + `) + + tpl, err := template.New("test-template").Funcs(template.FuncMap{ + "tr": Tr, + }).Parse(`{{ tr "test-key" .Value }}`) + require.NoError(t, err) + + data := struct { + Value string + }{ + "value", + } + var buf bytes.Buffer + require.NoError(t, tpl.Execute(&buf, data)) + + require.Equal(t, "test-key-translated value", buf.String()) +} + +func TestTranslationWithQuotedStrings(t *testing.T) { + setPo(` + msgid "test-key \"quoted\"" + msgstr "test-key-translated" + `) + + require.Equal(t, "test-key-translated", Tr("test-key \"quoted\"")) + require.Equal(t, "test-key-translated", Tr(`test-key "quoted"`)) +} + +func TestTranslationWithLineBreaks(t *testing.T) { + setPo(` + msgid "test-key \"quoted\"\n" + "new line" + msgstr "test-key-translated" + `) + + require.Equal(t, "test-key-translated", Tr("test-key \"quoted\"\nnew line")) + require.Equal(t, "test-key-translated", Tr(`test-key "quoted" +new line`)) +} From 6c8aa1e8a915ed960b62ee6241052671f30ad34d Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 22:03:07 -0300 Subject: [PATCH 38/49] fix po parsing correctness and implement tests --- i18n/cmd/po/catalog.go | 15 +++++++-- i18n/cmd/po/catalog_test.go | 61 +++++++++++++++++++++++++++++++++++++ i18n/cmd/po/merge_test.go | 47 ++++++++++++++++++++++++++++ i18n/cmd/po/parser.go | 14 ++++++--- i18n/cmd/po/parser_test.go | 42 +++++++++++++++++++++++++ 5 files changed, 172 insertions(+), 7 deletions(-) create mode 100644 i18n/cmd/po/catalog_test.go create mode 100644 i18n/cmd/po/merge_test.go create mode 100644 i18n/cmd/po/parser_test.go diff --git a/i18n/cmd/po/catalog.go b/i18n/cmd/po/catalog.go index 61322e93194..d90bcc27e5a 100644 --- a/i18n/cmd/po/catalog.go +++ b/i18n/cmd/po/catalog.go @@ -91,10 +91,19 @@ func (catalog *MessageCatalog) Write(w io.Writer) { func printValue(w io.Writer, field, value string) { if strings.Contains(value, "\n") { fmt.Fprintf(w, "%s ", field) - for _, line := range strings.Split(value, "\n") { - fmt.Fprintf(w, "\"%s\"\n", strings.ReplaceAll(line, `"`, `\"`)) + lines := strings.Split(value, "\n") + for i, line := range lines { + if i == len(lines)-1 { + fmt.Fprintf(w, "\"%s\"\n", escape(line)) + } else { + fmt.Fprintf(w, "\"%s\\n\"\n", escape(line)) + } } } else { - fmt.Fprintf(w, "%s \"%s\"\n", field, strings.ReplaceAll(value, `"`, `\"`)) + fmt.Fprintf(w, "%s \"%s\"\n", field, escape(value)) } } + +func escape(value string) string { + return strings.ReplaceAll(value, `"`, `\"`) +} diff --git a/i18n/cmd/po/catalog_test.go b/i18n/cmd/po/catalog_test.go new file mode 100644 index 00000000000..85b61f1a9db --- /dev/null +++ b/i18n/cmd/po/catalog_test.go @@ -0,0 +1,61 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package po + +import ( + "bytes" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestCatalogWriter(t *testing.T) { + var catalog MessageCatalog + catalog.Add("\"test-id\"", "test-value", []string{"# comment A", "# comment B"}) + catalog.Add("test-id\nmultiline", "test-value\nmultiline", []string{}) + catalog.Add(` + test-id + backquoted + `, ` + test-value + backquoted + `, []string{}) + + var buf bytes.Buffer + catalog.Write(&buf) + + require.Equal(t, `msgid "\n" +" test-id\n" +" backquoted\n" +" " +msgstr "\n" +" test-value\n" +" backquoted\n" +" " + +# comment A +# comment B +msgid "\"test-id\"" +msgstr "test-value" + +msgid "test-id\n" +"multiline" +msgstr "test-value\n" +"multiline" + +`, buf.String()) + +} diff --git a/i18n/cmd/po/merge_test.go b/i18n/cmd/po/merge_test.go new file mode 100644 index 00000000000..2540a4c7182 --- /dev/null +++ b/i18n/cmd/po/merge_test.go @@ -0,0 +1,47 @@ +package po + +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestMerge(t *testing.T) { + r := strings.NewReader(` +msgid "a" +msgstr "" + +msgid "b" +msgstr "value-b" + `) + catalogA := ParseReader(r) + + r = strings.NewReader(` +msgid "a" +msgstr "value-a" + +msgid "b" +msgstr "value-b" + +msgid "c" +msgstr "value-c" + `) + + catalogB := ParseReader(r) + + mergedCatalog := Merge(catalogA, catalogB) + + var buf bytes.Buffer + mergedCatalog.Write(&buf) + + require.Equal(t, `msgid "a" +msgstr "value-a" + +msgid "b" +msgstr "value-b" + +`, buf.String()) + +} diff --git a/i18n/cmd/po/parser.go b/i18n/cmd/po/parser.go index 4d2772a9e12..0d5ebf85e63 100644 --- a/i18n/cmd/po/parser.go +++ b/i18n/cmd/po/parser.go @@ -18,6 +18,7 @@ package po import ( "bufio" "fmt" + "io" "os" "strconv" "strings" @@ -36,7 +37,12 @@ func Parse(filename string) MessageCatalog { os.Exit(1) } - scanner := bufio.NewScanner(file) + return ParseReader(file) +} + +// ParseReader parses the PO file into a MessageCatalog +func ParseReader(r io.Reader) MessageCatalog { + scanner := bufio.NewScanner(r) return parseCatalog(scanner) } @@ -89,7 +95,7 @@ func parseCatalog(scanner *bufio.Scanner) MessageCatalog { } if state == StateMessageID && strings.HasPrefix(line, "\"") { - id += "\n" + mustUnquote(line) + id += mustUnquote(line) continue } @@ -100,7 +106,7 @@ func parseCatalog(scanner *bufio.Scanner) MessageCatalog { } if state == StateMessageValue && strings.HasPrefix(line, "\"") { - value += "\n" + mustUnquote(line) + value += mustUnquote(line) continue } } @@ -114,7 +120,7 @@ func mustUnquote(line string) string { fmt.Println(err.Error()) os.Exit(1) } - return strings.ReplaceAll(v, "\n", "\\n") + return v } func fileExists(filename string) bool { diff --git a/i18n/cmd/po/parser_test.go b/i18n/cmd/po/parser_test.go new file mode 100644 index 00000000000..010cb574d71 --- /dev/null +++ b/i18n/cmd/po/parser_test.go @@ -0,0 +1,42 @@ +// This file is part of arduino-cli. +// +// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) +// +// This software is released under the GNU General Public License version 3, +// which covers the main part of arduino-cli. +// The terms of this license can be found at: +// https://www.gnu.org/licenses/gpl-3.0.en.html +// +// You can be released from the requirements of the above licenses by purchasing +// a commercial license. Buying such a license is mandatory if you want to +// modify or otherwise use the software for commercial activities involving the +// Arduino software without disclosing the source code of your own applications. +// To purchase a commercial license, send an email to license@arduino.cc. + +package po + +import ( + "bytes" + "strings" + "testing" + + "github.com/stretchr/testify/require" +) + +func TestParser(t *testing.T) { + r := strings.NewReader(` +msgid "\"a\"\nline" +msgstr "value\nline" + `) + catalog := ParseReader(r) + + var buf bytes.Buffer + catalog.Write(&buf) + + require.Equal(t, `msgid "\"a\"\n" +"line" +msgstr "value\n" +"line" + +`, buf.String()) +} From eec56098e5f47456e273307eb8a6033b2ba7ab5d Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 18 May 2020 22:38:53 -0300 Subject: [PATCH 39/49] fix configuration path search tests --- configuration/configuration.go | 18 ++++++++++++------ .../configuration_test.go | 9 +++------ 2 files changed, 15 insertions(+), 12 deletions(-) rename cli/cli_test.go => configuration/configuration_test.go (91%) diff --git a/configuration/configuration.go b/configuration/configuration.go index 3c907477192..66c089bd162 100644 --- a/configuration/configuration.go +++ b/configuration/configuration.go @@ -206,12 +206,7 @@ func FindConfigFile() string { return searchCwdForConfig() } -func searchCwdForConfig() string { - cwd, err := os.Getwd() - - if err != nil { - return "" - } +func searchConfigTree(cwd string) string { // go back up to root and search for the config file for { @@ -230,4 +225,15 @@ func searchCwdForConfig() string { return "" } } + +} + +func searchCwdForConfig() string { + cwd, err := os.Getwd() + + if err != nil { + return "" + } + + return searchConfigTree(cwd) } diff --git a/cli/cli_test.go b/configuration/configuration_test.go similarity index 91% rename from cli/cli_test.go rename to configuration/configuration_test.go index 72ee80a1eac..820d19c2f50 100644 --- a/cli/cli_test.go +++ b/configuration/configuration_test.go @@ -13,10 +13,7 @@ // Arduino software without disclosing the source code of your own applications. // To purchase a commercial license, send an email to license@arduino.cc. -// These tests are mocked and won't work on OSX -// +build !darwin - -package cli +package configuration import ( "fmt" @@ -46,7 +43,7 @@ func TestSearchConfigTreeSameFolder(t *testing.T) { defer os.RemoveAll(tmp) _, err := os.Create(filepath.Join(tmp, "arduino-cli.yaml")) require.Nil(t, err) - require.Equal(t, searchConfigTree(tmp), tmp) + require.Equal(t, tmp, searchConfigTree(tmp)) } func TestSearchConfigTreeInParent(t *testing.T) { @@ -57,7 +54,7 @@ func TestSearchConfigTreeInParent(t *testing.T) { require.Nil(t, err) _, err = os.Create(filepath.Join(tmp, "arduino-cli.yaml")) require.Nil(t, err) - require.Equal(t, searchConfigTree(target), tmp) + require.Equal(t, tmp, searchConfigTree(target)) } var result string From 9007746504e2585e0a4668e203bfed3c35630889 Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 22 May 2020 11:48:48 -0300 Subject: [PATCH 40/49] update catalog command to find go files --- Taskfile.yml | 2 +- i18n/cmd/commands/catalog/generate_catalog.go | 17 +++++++++++++++-- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Taskfile.yml b/Taskfile.yml index fdc46e17946..58e8b05fa0e 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -118,7 +118,7 @@ tasks: i18n:update: desc: Updates i18n files cmds: - - find . -type f -name "*.go" | xargs go run ./i18n/cmd/main.go catalog generate > ./i18n/data/en.po + - go run ./i18n/cmd/main.go catalog generate . > ./i18n/data/en.po - go run ./i18n/cmd/main.go catalog update -l {{.I18N_LANGS}} ./i18n/data - go generate ./i18n diff --git a/i18n/cmd/commands/catalog/generate_catalog.go b/i18n/cmd/commands/catalog/generate_catalog.go index a71dabf2c73..c895660867a 100644 --- a/i18n/cmd/commands/catalog/generate_catalog.go +++ b/i18n/cmd/commands/catalog/generate_catalog.go @@ -17,19 +17,32 @@ package catalog import ( "os" + "path/filepath" "github.com/arduino/arduino-cli/i18n/cmd/ast" "github.com/spf13/cobra" ) var generateCatalogCommand = &cobra.Command{ - Use: "generate [source files]", + Use: "generate [input folder]", Short: "generates the en catalog from source files", Args: cobra.MinimumNArgs(1), Run: generateCatalog, } func generateCatalog(cmd *cobra.Command, args []string) { - catalog := ast.GenerateCatalog(args) + + folder := args[0] + files := []string{} + filepath.Walk(folder, func(name string, info os.FileInfo, err error) error { + if err != nil || info.IsDir() || filepath.Ext(name) != ".go" { + return nil + } + + files = append(files, name) + return nil + }) + + catalog := ast.GenerateCatalog(files) catalog.Write(os.Stdout) } From 2d3cf92100f2c1d83bd72a8ebc8e02355ed8ea7b Mon Sep 17 00:00:00 2001 From: Henrique Date: Fri, 22 May 2020 11:49:10 -0300 Subject: [PATCH 41/49] update catalog with new path --- i18n/data/en.po | 16 ++++++++-------- i18n/data/pt_BR.po | 16 ++++++++-------- i18n/rice-box.go | 14 +++++++------- 3 files changed, 23 insertions(+), 23 deletions(-) diff --git a/i18n/data/en.po b/i18n/data/en.po index 3d0f64e0456..7129df7e31e 100644 --- a/i18n/data/en.po +++ b/i18n/data/en.po @@ -1,35 +1,35 @@ msgid "" msgstr "" -#: ./cli/usage.go:31 +#: cli/usage.go:31 msgid "Additional help topics:" msgstr "Additional help topics:" -#: ./cli/usage.go:26 +#: cli/usage.go:26 msgid "Aliases:" msgstr "Aliases:" -#: ./cli/usage.go:28 +#: cli/usage.go:28 msgid "Available Commands:" msgstr "Available Commands:" -#: ./cli/usage.go:27 +#: cli/usage.go:27 msgid "Examples:" msgstr "Examples:" -#: ./cli/usage.go:29 +#: cli/usage.go:29 msgid "Flags:" msgstr "Flags:" -#: ./cli/usage.go:30 +#: cli/usage.go:30 msgid "Global Flags:" msgstr "Global Flags:" -#: ./cli/usage.go:25 +#: cli/usage.go:25 msgid "Usage:" msgstr "Usage:" -#: ./cli/usage.go:32 +#: cli/usage.go:32 msgid "Use %s for more information about a command." msgstr "Use %s for more information about a command." diff --git a/i18n/data/pt_BR.po b/i18n/data/pt_BR.po index 410d4b6f324..90a16da7c57 100644 --- a/i18n/data/pt_BR.po +++ b/i18n/data/pt_BR.po @@ -1,35 +1,35 @@ msgid "" msgstr "" -#: ./cli/usage.go:31 +#: cli/usage.go:31 msgid "Additional help topics:" msgstr "" -#: ./cli/usage.go:26 +#: cli/usage.go:26 msgid "Aliases:" msgstr "" -#: ./cli/usage.go:28 +#: cli/usage.go:28 msgid "Available Commands:" msgstr "" -#: ./cli/usage.go:27 +#: cli/usage.go:27 msgid "Examples:" msgstr "" -#: ./cli/usage.go:29 +#: cli/usage.go:29 msgid "Flags:" msgstr "" -#: ./cli/usage.go:30 +#: cli/usage.go:30 msgid "Global Flags:" msgstr "" -#: ./cli/usage.go:25 +#: cli/usage.go:25 msgid "Usage:" msgstr "" -#: ./cli/usage.go:32 +#: cli/usage.go:32 msgid "Use %s for more information about a command." msgstr "" diff --git a/i18n/rice-box.go b/i18n/rice-box.go index a44d7e125c4..910d9d250d1 100644 --- a/i18n/rice-box.go +++ b/i18n/rice-box.go @@ -11,27 +11,27 @@ func init() { // define files file2 := &embedded.EmbeddedFile{ Filename: ".gitkeep", - FileModTime: time.Unix(1589335267, 0), + FileModTime: time.Unix(1589851571, 0), Content: string(""), } file3 := &embedded.EmbeddedFile{ Filename: "en.po", - FileModTime: time.Unix(1589846460, 0), + FileModTime: time.Unix(1590158852, 0), - Content: string("msgid \"\"\nmsgstr \"\"\n\n#: ./cli/usage.go:31\nmsgid \"Additional help topics:\"\nmsgstr \"Additional help topics:\"\n\n#: ./cli/usage.go:26\nmsgid \"Aliases:\"\nmsgstr \"Aliases:\"\n\n#: ./cli/usage.go:28\nmsgid \"Available Commands:\"\nmsgstr \"Available Commands:\"\n\n#: ./cli/usage.go:27\nmsgid \"Examples:\"\nmsgstr \"Examples:\"\n\n#: ./cli/usage.go:29\nmsgid \"Flags:\"\nmsgstr \"Flags:\"\n\n#: ./cli/usage.go:30\nmsgid \"Global Flags:\"\nmsgstr \"Global Flags:\"\n\n#: ./cli/usage.go:25\nmsgid \"Usage:\"\nmsgstr \"Usage:\"\n\n#: ./cli/usage.go:32\nmsgid \"Use %s for more information about a command.\"\nmsgstr \"Use %s for more information about a command.\"\n\n"), + Content: string("msgid \"\"\nmsgstr \"\"\n\n#: cli/usage.go:31\nmsgid \"Additional help topics:\"\nmsgstr \"Additional help topics:\"\n\n#: cli/usage.go:26\nmsgid \"Aliases:\"\nmsgstr \"Aliases:\"\n\n#: cli/usage.go:28\nmsgid \"Available Commands:\"\nmsgstr \"Available Commands:\"\n\n#: cli/usage.go:27\nmsgid \"Examples:\"\nmsgstr \"Examples:\"\n\n#: cli/usage.go:29\nmsgid \"Flags:\"\nmsgstr \"Flags:\"\n\n#: cli/usage.go:30\nmsgid \"Global Flags:\"\nmsgstr \"Global Flags:\"\n\n#: cli/usage.go:25\nmsgid \"Usage:\"\nmsgstr \"Usage:\"\n\n#: cli/usage.go:32\nmsgid \"Use %s for more information about a command.\"\nmsgstr \"Use %s for more information about a command.\"\n\n"), } file4 := &embedded.EmbeddedFile{ Filename: "pt_BR.po", - FileModTime: time.Unix(1589846461, 0), + FileModTime: time.Unix(1590158853, 0), - Content: string("msgid \"\"\nmsgstr \"\"\n\n#: ./cli/usage.go:31\nmsgid \"Additional help topics:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:26\nmsgid \"Aliases:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:28\nmsgid \"Available Commands:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:27\nmsgid \"Examples:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:29\nmsgid \"Flags:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:30\nmsgid \"Global Flags:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:25\nmsgid \"Usage:\"\nmsgstr \"\"\n\n#: ./cli/usage.go:32\nmsgid \"Use %s for more information about a command.\"\nmsgstr \"\"\n\n"), + Content: string("msgid \"\"\nmsgstr \"\"\n\n#: cli/usage.go:31\nmsgid \"Additional help topics:\"\nmsgstr \"\"\n\n#: cli/usage.go:26\nmsgid \"Aliases:\"\nmsgstr \"\"\n\n#: cli/usage.go:28\nmsgid \"Available Commands:\"\nmsgstr \"\"\n\n#: cli/usage.go:27\nmsgid \"Examples:\"\nmsgstr \"\"\n\n#: cli/usage.go:29\nmsgid \"Flags:\"\nmsgstr \"\"\n\n#: cli/usage.go:30\nmsgid \"Global Flags:\"\nmsgstr \"\"\n\n#: cli/usage.go:25\nmsgid \"Usage:\"\nmsgstr \"\"\n\n#: cli/usage.go:32\nmsgid \"Use %s for more information about a command.\"\nmsgstr \"\"\n\n"), } // define dirs dir1 := &embedded.EmbeddedDir{ Filename: "", - DirModTime: time.Unix(1589846461, 0), + DirModTime: time.Unix(1590158853, 0), ChildFiles: []*embedded.EmbeddedFile{ file2, // ".gitkeep" file3, // "en.po" @@ -46,7 +46,7 @@ func init() { // register embeddedBox embedded.RegisterEmbeddedBox(`./data`, &embedded.EmbeddedBox{ Name: `./data`, - Time: time.Unix(1589846461, 0), + Time: time.Unix(1590158853, 0), Dirs: map[string]*embedded.EmbeddedDir{ "": dir1, }, From 4d6e3534d701d0fa6092c59bb54067ab28194149 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 25 May 2020 08:33:32 -0300 Subject: [PATCH 42/49] fix docsgen command --- docsgen/main.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docsgen/main.go b/docsgen/main.go index d3286a117e8..9e8cf837a61 100644 --- a/docsgen/main.go +++ b/docsgen/main.go @@ -28,7 +28,7 @@ func main() { log.Fatal("Please provide output folder") } - cli := cli.ArduinoCli + cli := cli.NewCommand() err := doc.GenMarkdownTree(cli, os.Args[1]) if err != nil { log.Fatal(err) From 2da2907d8a4ef77a7fef971b5a9a9fd0a52944ed Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 25 May 2020 08:44:25 -0300 Subject: [PATCH 43/49] remove dependency on shell script for windows compat --- Taskfile.yml | 10 ++++++++-- i18n/embed-i18n.sh | 4 ---- i18n/locale.go | 2 -- 3 files changed, 8 insertions(+), 8 deletions(-) delete mode 100755 i18n/embed-i18n.sh diff --git a/Taskfile.yml b/Taskfile.yml index 58e8b05fa0e..1e8a626b162 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -120,13 +120,13 @@ tasks: cmds: - go run ./i18n/cmd/main.go catalog generate . > ./i18n/data/en.po - go run ./i18n/cmd/main.go catalog update -l {{.I18N_LANGS}} ./i18n/data - - go generate ./i18n + - task: i18n:generate i18n:pull: desc: Pull i18n files from transifex cmds: - go run ./i18n/cmd/main.go transifex pull -l {{.I18N_LANGS}} ./i18n/data - - go generate ./i18n + - task: i18n:generate i18n:push: desc: Push i18n files to transifex @@ -139,6 +139,12 @@ tasks: - task: i18n:update - git add -N ./i18n/data - git diff --exit-code ./i18n/data &> /dev/null || echo "The i18n message catalog was updated, commit the changes before proceeding" + + i18n:generate: + desc: Generate embedded i18n catalog files + cmds: + - git add -N ./i18n/data + - git diff --exit-code ./i18n/data &> /dev/null || cd ./i18n && rice embed-go vars: # all modules of this project except for "legacy/..." module DEFAULT_TARGETS: diff --git a/i18n/embed-i18n.sh b/i18n/embed-i18n.sh deleted file mode 100755 index 02194448f73..00000000000 --- a/i18n/embed-i18n.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh - -git add -N ./data -git diff --exit-code ./data &> /dev/null || rice embed-go \ No newline at end of file diff --git a/i18n/locale.go b/i18n/locale.go index ebc1991e283..9e9b899bd2a 100644 --- a/i18n/locale.go +++ b/i18n/locale.go @@ -15,8 +15,6 @@ package i18n -//go:generate ./embed-i18n.sh - import ( "os" "path/filepath" From 450aa605cfa3f3017093b7cead76a8343b207452 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 25 May 2020 08:56:48 -0300 Subject: [PATCH 44/49] fix test workflow --- .github/workflows/test.yaml | 1 + Taskfile.yml | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index dc6df0487cd..d097ed50c01 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -35,6 +35,7 @@ jobs: go get github.com/golangci/govet go get golang.org/x/lint/golint go get github.com/golang/protobuf/protoc-gen-go + go get github.com/GeertJohan/go.rice/rice shell: bash - name: Install Taskfile diff --git a/Taskfile.yml b/Taskfile.yml index 1e8a626b162..f2544b07385 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -144,7 +144,7 @@ tasks: desc: Generate embedded i18n catalog files cmds: - git add -N ./i18n/data - - git diff --exit-code ./i18n/data &> /dev/null || cd ./i18n && rice embed-go + - git diff --exit-code ./i18n/data &> /dev/null || (cd ./i18n && rice embed-go) vars: # all modules of this project except for "legacy/..." module DEFAULT_TARGETS: From 98b8e16afaba7816441be149a55d82fe700674c4 Mon Sep 17 00:00:00 2001 From: Henrique Date: Mon, 25 May 2020 09:03:42 -0300 Subject: [PATCH 45/49] update setup-go to v2 --- .github/workflows/test.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yaml b/.github/workflows/test.yaml index d097ed50c01..94c7fe1ca04 100644 --- a/.github/workflows/test.yaml +++ b/.github/workflows/test.yaml @@ -23,7 +23,7 @@ jobs: uses: actions/checkout@master - name: Install Go - uses: actions/setup-go@v1 + uses: actions/setup-go@v2 with: go-version: '1.14' From 672fc5e58ac22ec920a3a5784ae2a0e12718fc41 Mon Sep 17 00:00:00 2001 From: Henrique Date: Tue, 26 May 2020 12:40:20 -0300 Subject: [PATCH 46/49] fail i18n:check task if catalog was not updated --- Taskfile.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Taskfile.yml b/Taskfile.yml index f2544b07385..ae315ff81b0 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -138,7 +138,7 @@ tasks: cmds: - task: i18n:update - git add -N ./i18n/data - - git diff --exit-code ./i18n/data &> /dev/null || echo "The i18n message catalog was updated, commit the changes before proceeding" + - git diff --exit-code ./i18n/data i18n:generate: desc: Generate embedded i18n catalog files From 9ffa200a438a6605d5dad778e568f6b200771fae Mon Sep 17 00:00:00 2001 From: Henrique Date: Tue, 26 May 2020 12:48:09 -0300 Subject: [PATCH 47/49] replace windows separator with forward slash --- i18n/cmd/ast/parser.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/i18n/cmd/ast/parser.go b/i18n/cmd/ast/parser.go index 943f2ae2aa4..8a510b34001 100644 --- a/i18n/cmd/ast/parser.go +++ b/i18n/cmd/ast/parser.go @@ -22,6 +22,7 @@ import ( "go/token" "os" "strconv" + "strings" "github.com/arduino/arduino-cli/i18n/cmd/po" ) @@ -74,7 +75,7 @@ func doFile(fset *token.FileSet, file *ast.File, catalog *po.MessageCatalog) { return true } - catalog.Add(msg, msg, []string{fmt.Sprintf("#: %s:%d", pos.Filename, pos.Line)}) + catalog.Add(msg, msg, []string{fmt.Sprintf("#: %s:%d", strings.ReplaceAll(pos.Filename, "\\", "/"), pos.Line)}) return true }) From 0d66bec8f1fa9dcba4bfe3c5edeccaf9d59fe07b Mon Sep 17 00:00:00 2001 From: Henrique Date: Tue, 26 May 2020 12:55:55 -0300 Subject: [PATCH 48/49] use filepath function to translate windows paths --- i18n/cmd/ast/parser.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/i18n/cmd/ast/parser.go b/i18n/cmd/ast/parser.go index 8a510b34001..9126a4ada8e 100644 --- a/i18n/cmd/ast/parser.go +++ b/i18n/cmd/ast/parser.go @@ -21,8 +21,8 @@ import ( "go/parser" "go/token" "os" + "path/filepath" "strconv" - "strings" "github.com/arduino/arduino-cli/i18n/cmd/po" ) @@ -75,7 +75,7 @@ func doFile(fset *token.FileSet, file *ast.File, catalog *po.MessageCatalog) { return true } - catalog.Add(msg, msg, []string{fmt.Sprintf("#: %s:%d", strings.ReplaceAll(pos.Filename, "\\", "/"), pos.Line)}) + catalog.Add(msg, msg, []string{fmt.Sprintf("#: %s:%d", filepath.ToSlash(pos.Filename), pos.Line)}) return true }) From 8e648331c9b51f633b0b73609190a7ae08db2c0c Mon Sep 17 00:00:00 2001 From: Henrique Date: Tue, 26 May 2020 13:23:31 -0300 Subject: [PATCH 49/49] only update en catalog --- Taskfile.yml | 2 +- i18n/cmd/commands/catalog/catalog.go | 1 - i18n/cmd/commands/catalog/update_catalog.go | 61 --------------------- 3 files changed, 1 insertion(+), 63 deletions(-) delete mode 100644 i18n/cmd/commands/catalog/update_catalog.go diff --git a/Taskfile.yml b/Taskfile.yml index ae315ff81b0..3f717d5fe96 100755 --- a/Taskfile.yml +++ b/Taskfile.yml @@ -119,7 +119,6 @@ tasks: desc: Updates i18n files cmds: - go run ./i18n/cmd/main.go catalog generate . > ./i18n/data/en.po - - go run ./i18n/cmd/main.go catalog update -l {{.I18N_LANGS}} ./i18n/data - task: i18n:generate i18n:pull: @@ -145,6 +144,7 @@ tasks: cmds: - git add -N ./i18n/data - git diff --exit-code ./i18n/data &> /dev/null || (cd ./i18n && rice embed-go) + vars: # all modules of this project except for "legacy/..." module DEFAULT_TARGETS: diff --git a/i18n/cmd/commands/catalog/catalog.go b/i18n/cmd/commands/catalog/catalog.go index f092d2d8293..25b69cfe4cc 100644 --- a/i18n/cmd/commands/catalog/catalog.go +++ b/i18n/cmd/commands/catalog/catalog.go @@ -25,5 +25,4 @@ var Command = &cobra.Command{ func init() { Command.AddCommand(generateCatalogCommand) - Command.AddCommand(updateCatalogCommand) } diff --git a/i18n/cmd/commands/catalog/update_catalog.go b/i18n/cmd/commands/catalog/update_catalog.go deleted file mode 100644 index e2b886d30a3..00000000000 --- a/i18n/cmd/commands/catalog/update_catalog.go +++ /dev/null @@ -1,61 +0,0 @@ -// This file is part of arduino-cli. -// -// Copyright 2020 ARDUINO SA (http://www.arduino.cc/) -// -// This software is released under the GNU General Public License version 3, -// which covers the main part of arduino-cli. -// The terms of this license can be found at: -// https://www.gnu.org/licenses/gpl-3.0.en.html -// -// You can be released from the requirements of the above licenses by purchasing -// a commercial license. Buying such a license is mandatory if you want to -// modify or otherwise use the software for commercial activities involving the -// Arduino software without disclosing the source code of your own applications. -// To purchase a commercial license, send an email to license@arduino.cc. - -package catalog - -import ( - "fmt" - "os" - "path" - - "github.com/arduino/arduino-cli/i18n/cmd/po" - "github.com/spf13/cobra" -) - -var updateCatalogCommand = &cobra.Command{ - Use: "update -l pt_BR [catalog folder]", - Short: "updates the language catalogs base on changes to the en catalog", - Args: cobra.ExactArgs(1), - Run: updateCatalog, -} - -var languages = []string{} - -func init() { - updateCatalogCommand.Flags().StringSliceVarP(&languages, "languages", "l", nil, "languages") - updateCatalogCommand.MarkFlagRequired("languages") -} - -func updateCatalog(cmd *cobra.Command, args []string) { - folder := args[0] - enCatalog := po.Parse(path.Join(folder, "en.po")) - - for _, lang := range languages { - filename := path.Join(folder, fmt.Sprintf("%s.po", lang)) - langCatalog := po.Parse(filename) - - mergedCatalog := po.Merge(enCatalog, langCatalog) - - os.Remove(filename) - file, err := os.OpenFile(path.Join(folder, fmt.Sprintf("%s.po", lang)), os.O_CREATE|os.O_RDWR, 0644) - - if err != nil { - fmt.Println(err.Error()) - os.Exit(1) - } - - mergedCatalog.Write(file) - } -}