diff options
-rw-r--r-- | cmd/gotop/main.go | 91 | ||||
-rw-r--r-- | go.mod | 2 | ||||
-rw-r--r-- | go.sum | 21 | ||||
-rw-r--r-- | translations/de_DE.toml | 44 | ||||
-rw-r--r-- | translations/en_US.toml | 74 | ||||
-rw-r--r-- | widgets/battery.go | 12 | ||||
-rw-r--r-- | widgets/batterygauge.go | 2 | ||||
-rw-r--r-- | widgets/cpu.go | 2 | ||||
-rw-r--r-- | widgets/disk.go | 10 | ||||
-rw-r--r-- | widgets/help.go | 51 |
10 files changed, 193 insertions, 116 deletions
diff --git a/cmd/gotop/main.go b/cmd/gotop/main.go index c917fc7..da4ee41 100644 --- a/cmd/gotop/main.go +++ b/cmd/gotop/main.go @@ -5,6 +5,7 @@ import ( "flag" "fmt" "io" + "io/ioutil" "log" "net/http" "os" @@ -18,8 +19,10 @@ import ( //_ "net/http/pprof" "github.com/VictoriaMetrics/metrics" + jj "github.com/cloudfoundry-attic/jibber_jabber" ui "github.com/gizak/termui/v3" "github.com/shibukawa/configdir" + "github.com/xxxserxxx/lingo" "github.com/xxxserxxx/opflag" "github.com/xxxserxxx/gotop/v4" @@ -27,7 +30,6 @@ import ( "github.com/xxxserxxx/gotop/v4/devices" "github.com/xxxserxxx/gotop/v4/layout" "github.com/xxxserxxx/gotop/v4/logging" - "github.com/xxxserxxx/gotop/v4/widgets" w "github.com/xxxserxxx/gotop/v4/widgets" ) @@ -50,6 +52,7 @@ var ( bar *w.StatusBar statusbar bool stderrLogger = log.New(os.Stderr, "", 0) + tr lingo.Translations ) func parseArgs() error { @@ -58,33 +61,27 @@ func parseArgs() error { for i, p := range cds { cpaths[i] = p.Path } - help := opflag.BoolP("help", "h", false, "Show this screen.") - color := opflag.StringP("color", "c", conf.Colorscheme.Name, "Set a colorscheme.") - opflag.IntVarP(&conf.GraphHorizontalScale, "graphscale", "S", conf.GraphHorizontalScale, "Graph scale factor, >0") - version := opflag.BoolP("version", "v", false, "Print version and exit.") - versioN := opflag.BoolP("", "V", false, "Print version and exit.") - opflag.BoolVarP(&conf.PercpuLoad, "percpu", "p", conf.PercpuLoad, "Show each CPU in the CPU widget.") - opflag.BoolVarP(&conf.AverageLoad, "averagecpu", "a", conf.AverageLoad, "Show average CPU in the CPU widget.") - fahrenheit := opflag.BoolP("fahrenheit", "f", conf.TempScale == 'F', "Show temperatures in fahrenheit.Show temperatures in fahrenheit.") - opflag.BoolVarP(&conf.Statusbar, "statusbar", "s", conf.Statusbar, "Show a statusbar with the time.") - opflag.DurationVarP(&conf.UpdateInterval, "rate", "r", conf.UpdateInterval, "Refresh frequency. Most time units accepted. `1m` = refresh every minute. `100ms` = refresh every 100ms.") - opflag.StringVarP(&conf.Layout, "layout", "l", conf.Layout, `Name of layout spec file for the UI. Use "-" to pipe.`) - opflag.StringVarP(&conf.NetInterface, "interface", "i", "all", "Select network interface. Several interfaces can be defined using comma separated values. Interfaces can also be ignored using `!`") - opflag.StringVarP(&conf.ExportPort, "export", "x", conf.ExportPort, "Enable metrics for export on the specified port.") - opflag.BoolVarP(&conf.Mbps, "mbps", "", conf.Mbps, "Show network rate as mbps.") - opflag.BoolVar(&conf.Test, "test", conf.Test, "Runs tests and exits with success/failure code.") - opflag.StringP("", "C", "", "Config file to use instead of default (MUST BE FIRST ARGUMENT)") - list := opflag.String("list", "", `List <devices|layouts|colorschemes|paths|keys> - devices: Prints out device names for filterable widgets - layouts: Lists build-in layouts - colorschemes: Lists built-in colorschemes - paths: List out configuration file search paths - widgets: Widgets that can be used in a layout - keys: Show the keyboard bindings.`) - wc := opflag.Bool("write-config", false, "Write out a default config file.") + help := opflag.BoolP("help", "h", false, tr.Value("args.help")) + color := opflag.StringP("color", "c", conf.Colorscheme.Name, tr.Value("args.color")) + opflag.IntVarP(&conf.GraphHorizontalScale, "graphscale", "S", conf.GraphHorizontalScale, tr.Value("args.scale")) + version := opflag.BoolP("version", "v", false, tr.Value("args.version")) + versioN := opflag.BoolP("", "V", false, tr.Value("args.version")) + opflag.BoolVarP(&conf.PercpuLoad, "percpu", "p", conf.PercpuLoad, tr.Value("args.percpu")) + opflag.BoolVarP(&conf.AverageLoad, "averagecpu", "a", conf.AverageLoad, tr.Value("args.cpuavg")) + fahrenheit := opflag.BoolP("fahrenheit", "f", conf.TempScale == 'F', tr.Value("args.temp")) + opflag.BoolVarP(&conf.Statusbar, "statusbar", "s", conf.Statusbar, tr.Value("args.statusbar")) + opflag.DurationVarP(&conf.UpdateInterval, "rate", "r", conf.UpdateInterval, tr.Value("args.rate")) + opflag.StringVarP(&conf.Layout, "layout", "l", conf.Layout, tr.Value("args.layout")) + opflag.StringVarP(&conf.NetInterface, "interface", "i", "all", tr.Value("args.net")) + opflag.StringVarP(&conf.ExportPort, "export", "x", conf.ExportPort, tr.Value("args.export")) + opflag.BoolVarP(&conf.Mbps, "mbps", "", conf.Mbps, tr.Value("args.mbps")) + opflag.BoolVar(&conf.Test, "test", conf.Test, tr.Value("args.test")) + opflag.StringP("", "C", "", tr.Value("args.conffile")) + list := opflag.String("list", "", tr.Value("args.list")) + wc := opflag.Bool("write-config", false, tr.Value("args.write")) opflag.SortFlags = false opflag.Usage = func() { - fmt.Fprintf(os.Stderr, "Usage: %s [options]\n\nOptions:\n", os.Args[0]) + fmt.Fprintf(os.Stderr, tr.Value("usage", os.Args[0])) opflag.PrintDefaults() } opflag.Parse() @@ -113,21 +110,22 @@ func parseArgs() error { case "colorschemes": fmt.Println(_colorschemes) case "paths": - fmt.Println("Loadable colorschemes & layouts, and the config file, are searched for, in order:") + fmt.Println(tr.Value("help.paths")) paths := make([]string, 0) for _, d := range conf.ConfigDir.QueryFolders(configdir.All) { paths = append(paths, d.Path) } fmt.Println(strings.Join(paths, "\n")) - fmt.Printf("\nThe log file is in %s\n", filepath.Join(conf.ConfigDir.QueryCacheFolder().Path, logging.LOGFILE)) + fmt.Println() + fmt.Println(tr.Value("help.log", filepath.Join(conf.ConfigDir.QueryCacheFolder().Path, logging.LOGFILE))) case "devices": listDevices() case "keys": - fmt.Println(widgets.KEYBINDS) + fmt.Println(tr.Value("widget.help")) case "widgets": fmt.Println(_widgets) default: - fmt.Printf("Unknown option \"%s\"; try layouts, colorschemes, keys, paths, or devices\n", *list) + fmt.Printf(tr.Value("error.unknownopt", *list)) os.Exit(1) } os.Exit(0) @@ -135,10 +133,10 @@ func parseArgs() error { if *wc { path, err := conf.Write() if err != nil { - fmt.Printf("Failed to write configuration file: %s\n", err) + fmt.Println(tr.Value("error.writefail", err.Error())) os.Exit(1) } - fmt.Printf("Config written to %s\n", path) + fmt.Println(tr.Value("help.written", path)) os.Exit(0) } return nil @@ -346,38 +344,53 @@ func main() { ec := run() if ec > 0 { if ec < 2 { - fmt.Printf("errors encountered; check the log file %s\n", filepath.Join(conf.ConfigDir.QueryCacheFolder().Path, logging.LOGFILE)) + logpath := filepath.Join(conf.ConfigDir.QueryCacheFolder().Path, logging.LOGFILE) + fmt.Println(tr.Value("error.checklog", logpath)) + fmt.Println(ioutil.ReadFile(logpath)) } } os.Exit(ec) } func run() int { + ling, err := lingo.New("en_US", "translations", nil) + if err != nil { + fmt.Printf("failed to load language files: %s\n", err) + return 2 + } + lang, err := jj.DetectIETF() + if err != nil { + fmt.Printf("failed to get language setting from environment: %s\n", err) + return 2 + } + lang = strings.Replace(lang, "-", "_", -1) + // Get the locale from the os + tr = ling.TranslationsForLocale(lang) conf = gotop.NewConfig() // Find the config file; look in (1) local, (2) user, (3) global // Check the last argument first fs := flag.NewFlagSet("config", flag.ContinueOnError) - cfg := fs.String("C", "", "Config file") + cfg := fs.String("C", "", tr.Value("configfile")) fs.SetOutput(bufio.NewWriter(nil)) fs.Parse(os.Args[1:]) if *cfg != "" { conf.ConfigFile = *cfg } - err := conf.Load() + err = conf.Load() if err != nil { - fmt.Printf("failed to parse config file: %s\n", err) + fmt.Println(tr.Value("error.configparse", err.Error())) return 2 } // Override with command line arguments err = parseArgs() if err != nil { - fmt.Printf("parsing CLI args: %s\n", err) + fmt.Println(tr.Value("error.cliparse", err.Error())) return 2 } logfile, err := logging.New(conf) if err != nil { - fmt.Printf("failed to setup log file: %v\n", err) + fmt.Println(tr.Value("logsetup", err.Error())) return 2 } defer logfile.Close() @@ -408,7 +421,7 @@ func run() int { defer ui.Close() setDefaultTermuiColors(conf) // done before initializing widgets to allow inheriting colors - help = w.NewHelpMenu() + help = w.NewHelpMenu(tr) if statusbar { bar = w.NewStatusBar() } @@ -1,6 +1,7 @@ module github.com/xxxserxxx/gotop/v4 require ( + github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d // indirect github.com/VictoriaMetrics/metrics v1.11.2 github.com/distatus/battery v0.9.0 @@ -11,6 +12,7 @@ require ( github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 github.com/shirou/gopsutil v2.20.3+incompatible github.com/stretchr/testify v1.4.0 + github.com/xxxserxxx/lingo v1.0.1 github.com/xxxserxxx/opflag v1.0.5 golang.org/x/sys v0.0.0-20200316230553-a7d97aace0b0 howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 // indirect @@ -1,24 +1,22 @@ +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d h1:G0m3OIz70MZUWq3EgK3CesDbo8upS2Vm9/P3FtgI+Jk= github.com/StackExchange/wmi v0.0.0-20190523213315-cbe66965904d/go.mod h1:3eOhrUMpNV+6aFIbp5/iudMxNCF27Vw2OZgy4xEx0Fg= github.com/VictoriaMetrics/metrics v1.11.2 h1:t/ceLP6SvagUqypCKU7cI7+tQn54+TIV/tGoxihHvx8= github.com/VictoriaMetrics/metrics v1.11.2/go.mod h1:LU2j9qq7xqZYXz8tF3/RQnB2z2MbZms5TDiIg9/NHiQ= github.com/cjbassi/drawille-go v0.0.0-20190126131713-27dc511fe6fd h1:XtfPmj9tQRilnrEmI1HjQhxXWRhEM+m8CACtaMJE/kM= github.com/cjbassi/drawille-go v0.0.0-20190126131713-27dc511fe6fd/go.mod h1:vjcQJUZJYD3MeVGhtZXSMnCHfUNZxsyYzJt90eCYxK4= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21 h1:Yg2hDs4b13Evkpj42FU2idX2cVXVFqQSheXYKM86Qsk= +github.com/cloudfoundry-attic/jibber_jabber v0.0.0-20151120183258-bcc4c8345a21/go.mod h1:MgJyK38wkzZbiZSKeIeFankxxSA8gayko/nr5x5bgBA= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/distatus/battery v0.9.0 h1:8NS5o00/j3Oh2xgocA6pQROTp5guoR+s8CZlWzHC4QM= github.com/distatus/battery v0.9.0/go.mod h1:gGO7GxHTi1zlRT+cAj8uGG0/8HFiqAeH0TJvoipnuPs= -github.com/gizak/termui/v3 v3.0.0 h1:NYTUG6ig/sJK05O5FyhWemwlVPO8ilNpvS/PgRtrKAE= -github.com/gizak/termui/v3 v3.0.0/go.mod h1:uinu2dMdtMI+FTIdEFUJQT5y+KShnhQRshvPblXq3lY= github.com/gizak/termui/v3 v3.1.0 h1:ZZmVDgwHl7gR7elfKf1xc4IudXZ5qqfDh4wExk4Iajc= github.com/gizak/termui/v3 v3.1.0/go.mod h1:bXQEBkJpzxUAKf0+xq9MSWAvWZlE7c+aidmyFlkYTrY= -github.com/go-ole/go-ole v1.2.4 h1:nNBDSCOigTSiarFpYE9J/KtEA1IOW4CNeqT9TQDqCxI= github.com/go-ole/go-ole v1.2.4/go.mod h1:XCwSNxSkXRo4vlyPy93sltvi/qJq0jqQhjqQNIwKuxM= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= -github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 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/mattn/go-runewidth v0.0.2/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= github.com/mattn/go-runewidth v0.0.4 h1:2BvfKmzob6Bmd4YsL0zygOqfdFnK7GR4QL06Do4/p7Y= @@ -28,32 +26,25 @@ github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZX github.com/nsf/termbox-go v0.0.0-20190121233118-02980233997d/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1 h1:lh3PyZvY+B9nFliSGTn5uFuqQQJGuNrD0MLCokv09ag= github.com/nsf/termbox-go v0.0.0-20200418040025-38ba6e5628f1/go.mod h1:IuKpRQcYE1Tfu+oAQqaLisqDeXgjyyltCfsaoYN18NQ= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0 h1:Xuk8ma/ibJ1fOy4Ee11vHhUFHQNpHhrBneOCNHVXS5w= github.com/shibukawa/configdir v0.0.0-20170330084843-e180dbdc8da0/go.mod h1:7AwjWCpdPhkSmNAgUv5C7EJ4AbmjEB3r047r3DXWu3Y= github.com/shirou/gopsutil v2.20.3+incompatible h1:0JVooMPsT7A7HqEYdydp/OfjSOYSjhXV7w1hkKj/NPQ= github.com/shirou/gopsutil v2.20.3+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/valyala/fastrand v1.0.0 h1:LUKT9aKer2dVQNUi3waewTbKV+7H17kvWFNKs2ObdkI= github.com/valyala/fastrand v1.0.0/go.mod h1:HWqCzkrkg6QXT8V2EXWvXCoow7vLwOFN002oeRzjapQ= github.com/valyala/histogram v1.0.1 h1:FzA7n2Tz/wKRMejgu3PV1vw3htAklTjjuoI6z3d4KDg= github.com/valyala/histogram v1.0.1/go.mod h1:lQy0xA4wUz2+IUnf97SivorsJIp8FxsnRd6x25q7Mto= +github.com/xxxserxxx/lingo v1.0.1 h1:lPexOb0HEqYB50EaJdjaYFNATT8JhTcXljbQmCuXygE= +github.com/xxxserxxx/lingo v1.0.1/go.mod h1:C2teIFiBLAmEhpLzRkwk7wP5R0eOoveXVYqD+5KOkAs= github.com/xxxserxxx/opflag v1.0.5 h1:2H4Qtl1qe+dSkEcGt+fBe2mQ8z14MgkWPqcLaoa6k90= github.com/xxxserxxx/opflag v1.0.5/go.mod h1:GWZtb3/tGGj5W1GE/JTyJAuqgxDxl1+jqDGAGM+P/p4= -golang.org/x/arch v0.0.0-20181203225421-5a4828bb7045/go.mod h1:cYlCBUl1MsqxdiKgmc4uh7TxZfWSFLOGSRR090WDxt8= golang.org/x/sys v0.0.0-20200316230553-a7d97aace0b0 h1:4Khi5GeNOkZS5DqSBRn4Sy7BE6GuxwOqARPqfurkdNk= golang.org/x/sys v0.0.0-20200316230553-a7d97aace0b0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25 h1:OKbAoGs4fGM5cPLlVQLZGYkFC8OnOfgo6tt0Smf9XhM= -golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5 h1:AQkaJpH+/FmqRjmXZPELom5zIERYZfwTjnHpfoVMQEc= howett.net/plist v0.0.0-20200419221736-3b63eb3a43b5/go.mod h1:vMygbs4qMhSZSc4lCUl2OEE+rDiIIJAIdR4m7MiMcm0= diff --git a/translations/de_DE.toml b/translations/de_DE.toml new file mode 100644 index 0000000..4633352 --- /dev/null +++ b/translations/de_DE.toml @@ -0,0 +1,44 @@ +configfile="Config file" +usage="Usage: {0} [options]\n\nOptions:\n" + + +[help] +paths="Loadable colorschemes & layouts, and the config file, are searched for, in order:" +log="The log file is in {0}" +written="Config written to {0}" + + +[args] +help="Hilfetext anzeigen." +color="Ein Farbschema feststellen." +scale="Stellen den Skalierungsfaktor ein, >0" +version="Zeigen die Version aus und beenden." +percpu="Show each CPU in the CPU widget." +cpuavg="Show average CPU in the CPU widget." +temp="Show temperatures in fahrenheit.Show temperatures in fahrenheit." +statusbar="Show a statusbar with the time." +rate="Refresh frequency. Most time units accepted. \"1m\" = refresh every minute. \"100ms\" = refresh every 100ms." +layout="Name of layout spec file for the UI. Use \"-\" to pipe." +net="Select network interface. Several interfaces can be defined using comma separated values. Interfaces can also be ignored using \"!\"" +export="Enable metrics for export on the specified port." +mbps="Show network rate as mbps." +test="Runs tests and exits with success/failure code." +conffile="Config file to use instead of default (MUST BE FIRST ARGUMENT)" +list=""" +List <devices|layouts|colorschemes|paths|keys> + devices: Prints out device names for filterable widgets + layouts: Lists build-in layouts + colorschemes: Lists built-in colorschemes + paths: List out configuration file search paths + widgets: Widgets that can be used in a layout + keys: Show the keyboard bindings.""" +write="Write out a default config file." + + +[errors] +configparse="failed to parse config file: {0}" +cliparse="parsing CLI args: {0}" +logsetup="failed to setup log file: {0}" +unknownopt="Unknown option \"{0}\"; try layouts, colorschemes, keys, paths, or devices\n" +writefail="Failed to write configuration file: {0}" +checklog="errors encountered; from {0}:" diff --git a/translations/en_US.toml b/translations/en_US.toml index 05cde16..bd66458 100644 --- a/translations/en_US.toml +++ b/translations/en_US.toml @@ -35,10 +35,70 @@ List <devices|layouts|colorschemes|paths|keys> write="Write out a default config file." -[errors] -configparse="failed to parse config file: {0}" -cliparse="parsing CLI args: {0}" -logsetup="failed to setup log file: {0}" -unknownopt="Unknown option \"{0}\"; try layouts, colorschemes, keys, paths, or devices\n" -writefail="Failed to write configuration file: {0}" -checklog="errors encountered; from {0}:" +[error] +configparse="0: failed to parse config file: {0}" +cliparse="1: parsing CLI args: {0}" +logsetup="2: failed to setup log file: {0}" +unknownopt="3: Unknown option \"{0}\"; try layouts, colorschemes, keys, paths, or devices\n" +writefail="4: Failed to write configuration file: {0}" +checklog="5: errors encountered; from {0}:" +metricsetup="6: error setting up {0} metrics: {1}" +nometrics="7: no metrics for {0} {0}" +fatalfetch="8: fatal error fetching {0} info: {1}" +recovfetch="9: recoverable error fetching {0} info; skipping {0}: {0}" +nodevfound="10: no usable {0} found" +setuperr="11: error setting up {0}: {1}" + + +[widget] +disk=" Disk Usage " +cpu=" CPU Usage " +gauge=" Power Level " +battery=" Battery Status " +batt= +help=""" +Quit: q or <C-c> + +Process navigation: + - k and <Up>: up + - j and <Down>: down + - <C-u>: half page up + - <C-d>: half page down + - <C-b>: full page up + - <C-f>: full page down + - gg and <Home>: jump to top + - G and <End>: jump to bottom + +Process actions: + - <Tab>: toggle process grouping + - dd: kill selected process or group of processes with SIGTERM (15) + - d3: kill selected process or group of processes with SIGQUIT (3) + - d9: kill selected process or group of processes with SIGKILL (9) + +Process sorting: + - c: CPU + - m: Mem + - p: PID + +Process filtering: + - /: start editing filter + - (while editing): + - <Enter>: accept filter + - <C-c> and <Escape>: clear filter + +CPU and Mem graph scaling: + - h: scale in + - l: scale out + +Network: + - b: toggle between mbps and scaled bytes per second +""" + + +[widget.disk] +disk="Disk" +mount="Mount" +used="Used" +free="Free" +rs="R/s" +ws="W/s" diff --git a/widgets/battery.go b/widgets/battery.go index 77b102f..7bc9ca6 100644 --- a/widgets/battery.go +++ b/widgets/battery.go @@ -23,7 +23,7 @@ func NewBatteryWidget(horizontalScale int) *BatteryWidget { LineGraph: ui.NewLineGraph(), updateInterval: time.Minute, } - self.Title = " Battery Status " + self.Title = tr.Value("widget.battery") self.HorizontalScale = horizontalScale // intentional duplicate @@ -45,7 +45,7 @@ func NewBatteryWidget(horizontalScale int) *BatteryWidget { func (b *BatteryWidget) EnableMetric() { bats, err := battery.GetAll() if err != nil { - log.Printf("error setting up metrics: %v", err) + log.Printf(tr.Value("error.metricsetup", "batt", err.Error())) return } for i, _ := range bats { @@ -60,7 +60,7 @@ func (b *BatteryWidget) EnableMetric() { } func makeID(i int) string { - return "Batt" + strconv.Itoa(i) + return tr.Value("widget.batt") + strconv.Itoa(i) } func (b *BatteryWidget) Scale(i int) { @@ -72,7 +72,7 @@ func (b *BatteryWidget) update() { if err != nil { switch errt := err.(type) { case battery.ErrFatal: - log.Printf("fatal error fetching battery info: %v", err) + log.Printf(tr.Value("error.fatalfetch", "batt", err.Error())) return case battery.Errors: batts := make([]*battery.Battery, 0) @@ -80,11 +80,11 @@ func (b *BatteryWidget) update() { if e == nil { batts = append(batts, batteries[i]) } else { - log.Printf("recoverable error fetching battery info; skipping battery: %v", e) + log.Printf(tr.Value("error.recovfetch"), "batt", e.Error()) } } if len(batts) < 1 { - log.Print("no usable batteries found") + log.Print(tr.Value("error.nodevfound", "batt")) return } batteries = batts diff --git a/widgets/batterygauge.go b/widgets/batterygauge.go index 135f223..bec3c43 100644 --- a/widgets/batterygauge.go +++ b/widgets/batterygauge.go @@ -18,7 +18,7 @@ type BatteryGauge struct { func NewBatteryGauge() *BatteryGauge { self := &BatteryGauge{Gauge: termui.NewGauge()} - self.Title = " Power Level " + self.Title = tr.Value("widget.gauge") self.update() diff --git a/widgets/cpu.go b/widgets/cpu.go index d8d9a50..207b231 100644 --- a/widgets/cpu.go +++ b/widgets/cpu.go @@ -32,7 +32,7 @@ func NewCPUWidget(updateInterval time.Duration, horizontalScale int, showAverage ShowPerCPULoad: showPerCPULoad, cpuLoads: make(map[string]float64), } - self.Title = " CPU Usage " + self.Title = tr.Value("cpu") self.HorizontalScale = horizontalScale if !(self.ShowAverageLoad || self.ShowPerCPULoad) { diff --git a/widgets/disk.go b/widgets/disk.go index f1921fd..716e631 100644 --- a/widgets/disk.go +++ b/widgets/disk.go @@ -37,8 +37,8 @@ func NewDiskWidget() *DiskWidget { updateInterval: time.Second, Partitions: make(map[string]*Partition), } - self.Title = " Disk Usage " - self.Header = []string{"Disk", "Mount", "Used", "Free", "R/s", "W/s"} + self.Title = tr.Value("widget.disk") + self.Header = []string{tr.Value("disk.disk"), tr.Value("disk.mount"), tr.Value("disk.used"), tr.Value("disk.free"), tr.Value("disk.rs"), tr.Value("disk.ws")} self.ColGap = 2 self.ColResizer = func() { self.ColWidths = []int{ @@ -73,7 +73,7 @@ func (disk *DiskWidget) EnableMetric() { func (disk *DiskWidget) update() { partitions, err := psDisk.Partitions(false) if err != nil { - log.Printf("failed to get disk partitions from gopsutil: %v", err) + log.Printf(tr.Value("error.setup", "disk-partitions", err.Error())) return } @@ -118,7 +118,7 @@ func (disk *DiskWidget) update() { for _, partition := range disk.Partitions { usage, err := psDisk.Usage(partition.MountPoint) if err != nil { - log.Printf("failed to get partition usage statistics from gopsutil: %v. partition: %v", err, partition) + log.Printf(tr.Value("error.recovfetch", "partition-"+partition.MountPoint+"-usage", err.Error())) continue } partition.UsedPercent = uint32(usage.UsedPercent + 0.5) @@ -127,7 +127,7 @@ func (disk *DiskWidget) update() { ioCounters, err := psDisk.IOCounters(partition.Device) if err != nil { - log.Printf("failed to get partition read/write info from gopsutil: %v. partition: %v", err, partition) + log.Printf(tr.Value("error.recovfetch", "partition-"+partition.Device+"-rw", err.Error())) continue } ioCounter := ioCounters[strings.Replace(partition.Device, "/dev/", "", -1)] diff --git a/widgets/help.go b/widgets/help.go index a2c38e4..fff71a7 100644 --- a/widgets/help.go +++ b/widgets/help.go @@ -5,52 +5,19 @@ import ( "strings" ui "github.com/gizak/termui/v3" + "github.com/xxxserxxx/lingo" ) -// KEYBINDS is the help text for the in-program shortcuts -const KEYBINDS = ` -Quit: q or <C-c> - -Process navigation: - - k and <Up>: up - - j and <Down>: down - - <C-u>: half page up - - <C-d>: half page down - - <C-b>: full page up - - <C-f>: full page down - - gg and <Home>: jump to top - - G and <End>: jump to bottom - -Process actions: - - <Tab>: toggle process grouping - - dd: kill selected process or group of processes with SIGTERM (15) - - d3: kill selected process or group of processes with SIGQUIT (3) - - d9: kill selected process or group of processes with SIGKILL (9) - -Process sorting: - - c: CPU - - m: Mem - - p: PID - -Process filtering: - - /: start editing filter - - (while editing): - - <Enter>: accept filter - - <C-c> and <Escape>: clear filter - -CPU and Mem graph scaling: - - h: scale in - - l: scale out - -Network: - - b: toggle between mbps and scaled bytes per second -` +var tr lingo.Translations +var keyBinds string type HelpMenu struct { ui.Block } -func NewHelpMenu() *HelpMenu { +func NewHelpMenu(tra lingo.Translations) *HelpMenu { + tr = tra + keyBinds = tr.Value("widgets.help") return &HelpMenu{ Block: *ui.NewBlock(), } @@ -58,12 +25,12 @@ func NewHelpMenu() *HelpMenu { func (help *HelpMenu) Resize(termWidth, termHeight int) { textWidth := 53 - for _, line := range strings.Split(KEYBINDS, "\n") { + for _, line := range strings.Split(keyBinds, "\n") { if textWidth < len(line) { textWidth = len(line) + 2 } } - textHeight := strings.Count(KEYBINDS, "\n") + 1 + textHeight := strings.Count(keyBinds, "\n") + 1 x := (termWidth - textWidth) / 2 y := (termHeight - textHeight) / 2 @@ -73,7 +40,7 @@ func (help *HelpMenu) Resize(termWidth, termHeight int) { func (help *HelpMenu) Draw(buf *ui.Buffer) { help.Block.Draw(buf) - for y, line := range strings.Split(KEYBINDS, "\n") { + for y, line := range strings.Split(keyBinds, "\n") { for x, rune := range line { buf.SetCell( ui.NewCell(rune, ui.Theme.Default), |