mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
Add support for user-configuration language tag specification. (#1038)
Adds a new top-level configuration key called "language": ```yaml wtf: langauge: "ja-JP" ``` Users can now define which BCP 47 language tag to use to format any text or numbers that currently support localization. Defaults to "en-CA". Acceptible values: any BCP 47 language tag recognized by the Go "language" package. Good luck to you figuring out what that cannonical list is. After a morning of trying to suss it out, I have no idea. Signed-off-by: Chris Cummer <chriscummer@me.com>
This commit is contained in:
parent
fd794707cd
commit
d7da659b8b
@ -5,6 +5,12 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/olebedev/config"
|
"github.com/olebedev/config"
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
"golang.org/x/text/message"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
defaultLanguageTag = "en-CA"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Module struct {
|
type Module struct {
|
||||||
@ -23,6 +29,7 @@ type Sigils struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Common defines a set of common configuration settings applicable to all modules
|
||||||
type Common struct {
|
type Common struct {
|
||||||
Module
|
Module
|
||||||
PositionSettings `help:"Defines where in the grid this module’s widget will be displayed."`
|
PositionSettings `help:"Defines where in the grid this module’s widget will be displayed."`
|
||||||
@ -36,6 +43,7 @@ type Common struct {
|
|||||||
Bordered bool `help:"Whether or not the module should be displayed with a border." values:"true, false" optional:"true" default:"true"`
|
Bordered bool `help:"Whether or not the module should be displayed with a border." values:"true, false" optional:"true" default:"true"`
|
||||||
Enabled bool `help:"Whether or not this module is executed and if its data displayed onscreen." values:"true, false" optional:"true" default:"false"`
|
Enabled bool `help:"Whether or not this module is executed and if its data displayed onscreen." values:"true, false" optional:"true" default:"false"`
|
||||||
Focusable bool `help:"Whether or not this module is focusable." values:"true, false" optional:"true" default:"false"`
|
Focusable bool `help:"Whether or not this module is focusable." values:"true, false" optional:"true" default:"false"`
|
||||||
|
LanguageTag string `help:"The BCP 47 langauge tag to localize text to." values:"Any supported BCP 47 language tag." optional:"true" default:"en-CA"`
|
||||||
RefreshInterval int `help:"How often, in seconds, this module will update its data." values:"A positive integer, 0..n." optional:"true"`
|
RefreshInterval int `help:"How often, in seconds, this module will update its data." values:"A positive integer, 0..n." optional:"true"`
|
||||||
Title string `help:"The title string to show when displaying this module" optional:"true"`
|
Title string `help:"The title string to show when displaying this module" optional:"true"`
|
||||||
|
|
||||||
@ -43,10 +51,10 @@ type Common struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewCommonSettingsFromModule returns a common settings configuration tailed to the given module
|
// NewCommonSettingsFromModule returns a common settings configuration tailed to the given module
|
||||||
func NewCommonSettingsFromModule(name, defaultTitle string, defaultFocusable bool, moduleConfig *config.Config, globalSettings *config.Config) *Common {
|
func NewCommonSettingsFromModule(name, defaultTitle string, defaultFocusable bool, moduleConfig *config.Config, globalConfig *config.Config) *Common {
|
||||||
baseColors := NewDefaultColorTheme()
|
baseColors := NewDefaultColorTheme()
|
||||||
|
|
||||||
colorsConfig, err := globalSettings.Get("wtf.colors")
|
colorsConfig, err := globalConfig.Get("wtf.colors")
|
||||||
if err != nil && strings.Contains(err.Error(), "Nonexistent map") {
|
if err != nil && strings.Contains(err.Error(), "Nonexistent map") {
|
||||||
// Create a default colors config to fill in for the missing one
|
// Create a default colors config to fill in for the missing one
|
||||||
// This comes into play when the configuration file does not contain a `colors:` key, i.e:
|
// This comes into play when the configuration file does not contain a `colors:` key, i.e:
|
||||||
@ -93,6 +101,7 @@ func NewCommonSettingsFromModule(name, defaultTitle string, defaultFocusable boo
|
|||||||
Config: moduleConfig,
|
Config: moduleConfig,
|
||||||
Enabled: moduleConfig.UBool("enabled", false),
|
Enabled: moduleConfig.UBool("enabled", false),
|
||||||
Focusable: moduleConfig.UBool("focusable", defaultFocusable),
|
Focusable: moduleConfig.UBool("focusable", defaultFocusable),
|
||||||
|
LanguageTag: globalConfig.UString("wtf.language", defaultLanguageTag),
|
||||||
RefreshInterval: moduleConfig.UInt("refreshInterval", 300),
|
RefreshInterval: moduleConfig.UInt("refreshInterval", 300),
|
||||||
Title: moduleConfig.UString("title", defaultTitle),
|
Title: moduleConfig.UString("title", defaultTitle),
|
||||||
|
|
||||||
@ -100,11 +109,10 @@ func NewCommonSettingsFromModule(name, defaultTitle string, defaultFocusable boo
|
|||||||
}
|
}
|
||||||
|
|
||||||
sigilsPath := "wtf.sigils"
|
sigilsPath := "wtf.sigils"
|
||||||
|
common.Sigils.Checkbox.Checked = globalConfig.UString(sigilsPath+".checkbox.checked", "x")
|
||||||
common.Sigils.Checkbox.Checked = globalSettings.UString(sigilsPath+".checkbox.checked", "x")
|
common.Sigils.Checkbox.Unchecked = globalConfig.UString(sigilsPath+".checkbox.unchecked", " ")
|
||||||
common.Sigils.Checkbox.Unchecked = globalSettings.UString(sigilsPath+".checkbox.unchecked", " ")
|
common.Sigils.Paging.Normal = globalConfig.UString(sigilsPath+".paging.normal", globalConfig.UString("wtf.paging.pageSigil", "*"))
|
||||||
common.Sigils.Paging.Normal = globalSettings.UString(sigilsPath+".paging.normal", globalSettings.UString("wtf.paging.pageSigil", "*"))
|
common.Sigils.Paging.Selected = globalConfig.UString(sigilsPath+".paging.select", globalConfig.UString("wtf.paging.selectedSigil", "_"))
|
||||||
common.Sigils.Paging.Selected = globalSettings.UString(sigilsPath+".paging.select", globalSettings.UString("wtf.paging.selectedSigil", "_"))
|
|
||||||
|
|
||||||
return &common
|
return &common
|
||||||
}
|
}
|
||||||
@ -141,6 +149,20 @@ func (common *Common) FocusChar() string {
|
|||||||
return fmt.Sprint(common.focusChar)
|
return fmt.Sprint(common.focusChar)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// LocalizedPrinter returns a message.Printer instance localized to the BCP 47 language
|
||||||
|
// configuration value defined in 'wtf.language' config. If none exists, it defaults to
|
||||||
|
// 'en-CA'. Use this to format numbers, etc.
|
||||||
|
func (common *Common) LocalizedPrinter() (*message.Printer, error) {
|
||||||
|
langTag, err := language.Parse(common.LanguageTag)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
prntr := message.NewPrinter(langTag)
|
||||||
|
|
||||||
|
return prntr, nil
|
||||||
|
}
|
||||||
|
|
||||||
func (common *Common) RowColor(idx int) string {
|
func (common *Common) RowColor(idx int) string {
|
||||||
if idx%2 == 0 {
|
if idx%2 == 0 {
|
||||||
return common.Colors.RowTheme.EvenForeground
|
return common.Colors.RowTheme.EvenForeground
|
||||||
|
@ -4,8 +4,6 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
ghb "github.com/google/go-github/v32/github"
|
ghb "github.com/google/go-github/v32/github"
|
||||||
"golang.org/x/text/language"
|
|
||||||
"golang.org/x/text/message"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (widget *Widget) display() {
|
func (widget *Widget) display() {
|
||||||
@ -124,13 +122,16 @@ func (widget *Widget) displayMyReviewRequests(repo *Repo, username string) strin
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (widget *Widget) displayStats(repo *Repo) string {
|
func (widget *Widget) displayStats(repo *Repo) string {
|
||||||
prntr := message.NewPrinter(language.English)
|
locPrinter, err := widget.settings.LocalizedPrinter()
|
||||||
|
if err != nil {
|
||||||
|
return err.Error()
|
||||||
|
}
|
||||||
|
|
||||||
str := fmt.Sprintf(
|
str := fmt.Sprintf(
|
||||||
" PRs: %s Issues: %s Stars: %s\n",
|
" PRs: %s Issues: %s Stars: %s\n",
|
||||||
prntr.Sprintf("%d", repo.PullRequestCount()),
|
locPrinter.Sprintf("%d", repo.PullRequestCount()),
|
||||||
prntr.Sprintf("%d", repo.IssueCount()),
|
locPrinter.Sprintf("%d", repo.IssueCount()),
|
||||||
prntr.Sprintf("%d", repo.StarCount()),
|
locPrinter.Sprintf("%d", repo.StarCount()),
|
||||||
)
|
)
|
||||||
|
|
||||||
return str
|
return str
|
||||||
|
@ -105,12 +105,14 @@ func (widget *Widget) content() (string, string, bool) {
|
|||||||
}
|
}
|
||||||
var str string
|
var str string
|
||||||
|
|
||||||
|
locPrinter, _ := widget.settings.LocalizedPrinter()
|
||||||
|
|
||||||
for idx, stream := range widget.topStreams {
|
for idx, stream := range widget.topStreams {
|
||||||
row := fmt.Sprintf(
|
row := fmt.Sprintf(
|
||||||
"[%s]%2d. [red]%s [white]%s",
|
"[%s]%2d. [red]%s [white]%s",
|
||||||
widget.RowColor(idx),
|
widget.RowColor(idx),
|
||||||
idx+1,
|
idx+1,
|
||||||
utils.PrettyNumber(float64(stream.ViewerCount)),
|
utils.PrettyNumber(locPrinter, float64(stream.ViewerCount)),
|
||||||
stream.Streamer,
|
stream.Streamer,
|
||||||
)
|
)
|
||||||
str += utils.HighlightableHelper(widget.View, row, idx, len(stream.Streamer))
|
str += utils.HighlightableHelper(widget.View, row, idx, len(stream.Streamer))
|
||||||
|
@ -5,7 +5,6 @@ import (
|
|||||||
"math"
|
"math"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/text/language"
|
|
||||||
"golang.org/x/text/message"
|
"golang.org/x/text/message"
|
||||||
|
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
@ -78,12 +77,10 @@ func Truncate(src string, maxLen int, withEllipse bool) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// PrettyNumber formats number as string with 1000 delimiters and, if necessary, rounds it to 2 decimals
|
// PrettyNumber formats number as string with 1000 delimiters and, if necessary, rounds it to 2 decimals
|
||||||
func PrettyNumber(number float64) string {
|
func PrettyNumber(prtr *message.Printer, number float64) string {
|
||||||
p := message.NewPrinter(language.English)
|
|
||||||
|
|
||||||
if number == math.Trunc(number) {
|
if number == math.Trunc(number) {
|
||||||
return p.Sprintf("%.0f", number)
|
return prtr.Sprintf("%.0f", number)
|
||||||
}
|
}
|
||||||
|
|
||||||
return p.Sprintf("%.2f", number)
|
return prtr.Sprintf("%.2f", number)
|
||||||
}
|
}
|
||||||
|
@ -5,6 +5,8 @@ import (
|
|||||||
|
|
||||||
"github.com/rivo/tview"
|
"github.com/rivo/tview"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
|
"golang.org/x/text/language"
|
||||||
|
"golang.org/x/text/message"
|
||||||
)
|
)
|
||||||
|
|
||||||
func Test_CenterText(t *testing.T) {
|
func Test_CenterText(t *testing.T) {
|
||||||
@ -45,15 +47,17 @@ func Test_Truncate(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func Test_PrettyNumber(t *testing.T) {
|
func Test_PrettyNumber(t *testing.T) {
|
||||||
assert.Equal(t, "1,000,000", PrettyNumber(1000000))
|
locPrinter := message.NewPrinter(language.English)
|
||||||
assert.Equal(t, "1,000,000.99", PrettyNumber(1000000.99))
|
|
||||||
assert.Equal(t, "1,000,000", PrettyNumber(1000000.00))
|
assert.Equal(t, "1,000,000", PrettyNumber(locPrinter, 1000000))
|
||||||
assert.Equal(t, "100,000", PrettyNumber(100000))
|
assert.Equal(t, "1,000,000.99", PrettyNumber(locPrinter, 1000000.99))
|
||||||
assert.Equal(t, "100,000.01", PrettyNumber(100000.009))
|
assert.Equal(t, "1,000,000", PrettyNumber(locPrinter, 1000000.00))
|
||||||
assert.Equal(t, "10,000", PrettyNumber(10000))
|
assert.Equal(t, "100,000", PrettyNumber(locPrinter, 100000))
|
||||||
assert.Equal(t, "1,000", PrettyNumber(1000))
|
assert.Equal(t, "100,000.01", PrettyNumber(locPrinter, 100000.009))
|
||||||
assert.Equal(t, "1,000", PrettyNumber(1000))
|
assert.Equal(t, "10,000", PrettyNumber(locPrinter, 10000))
|
||||||
assert.Equal(t, "100", PrettyNumber(100))
|
assert.Equal(t, "1,000", PrettyNumber(locPrinter, 1000))
|
||||||
assert.Equal(t, "0", PrettyNumber(0))
|
assert.Equal(t, "1,000", PrettyNumber(locPrinter, 1000))
|
||||||
assert.Equal(t, "0.10", PrettyNumber(0.1))
|
assert.Equal(t, "100", PrettyNumber(locPrinter, 100))
|
||||||
|
assert.Equal(t, "0", PrettyNumber(locPrinter, 0))
|
||||||
|
assert.Equal(t, "0.10", PrettyNumber(locPrinter, 0.1))
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user