mirror of
https://github.com/taigrr/wtf
synced 2025-01-18 04:03:14 -08:00
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>
215 lines
8.1 KiB
Go
215 lines
8.1 KiB
Go
package cfg
|
||
|
||
import (
|
||
"fmt"
|
||
"strings"
|
||
|
||
"github.com/olebedev/config"
|
||
"golang.org/x/text/language"
|
||
"golang.org/x/text/message"
|
||
)
|
||
|
||
const (
|
||
defaultLanguageTag = "en-CA"
|
||
)
|
||
|
||
type Module struct {
|
||
Name string
|
||
Type string
|
||
}
|
||
|
||
type Sigils struct {
|
||
Checkbox struct {
|
||
Checked string
|
||
Unchecked string
|
||
}
|
||
Paging struct {
|
||
Normal string
|
||
Selected string
|
||
}
|
||
}
|
||
|
||
// Common defines a set of common configuration settings applicable to all modules
|
||
type Common struct {
|
||
Module
|
||
PositionSettings `help:"Defines where in the grid this module’s widget will be displayed."`
|
||
Sigils
|
||
|
||
Colors ColorTheme
|
||
Config *config.Config
|
||
|
||
DocPath string
|
||
|
||
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"`
|
||
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"`
|
||
Title string `help:"The title string to show when displaying this module" optional:"true"`
|
||
|
||
focusChar int `help:"Define one of the number keys as a short cut key to access the widget." optional:"true"`
|
||
}
|
||
|
||
// NewCommonSettingsFromModule returns a common settings configuration tailed to the given module
|
||
func NewCommonSettingsFromModule(name, defaultTitle string, defaultFocusable bool, moduleConfig *config.Config, globalConfig *config.Config) *Common {
|
||
baseColors := NewDefaultColorTheme()
|
||
|
||
colorsConfig, err := globalConfig.Get("wtf.colors")
|
||
if err != nil && strings.Contains(err.Error(), "Nonexistent map") {
|
||
// 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:
|
||
//
|
||
// wtf:
|
||
// # colors: <- missing
|
||
// refreshInterval: 1
|
||
// openFileUtil: "open"
|
||
//
|
||
colorsConfig, _ = NewDefaultColorConfig()
|
||
}
|
||
|
||
// And finally create a third instance to be the final default fallback in case there are empty or nil values in
|
||
// the colors extracted from the config file (aka colorsConfig)
|
||
defaultColorTheme := NewDefaultColorTheme()
|
||
|
||
baseColors.BorderTheme.Focusable = moduleConfig.UString("colors.border.focusable", colorsConfig.UString("border.focusable", defaultColorTheme.BorderTheme.Focusable))
|
||
baseColors.BorderTheme.Focused = moduleConfig.UString("colors.border.focused", colorsConfig.UString("border.focused", defaultColorTheme.BorderTheme.Focused))
|
||
baseColors.BorderTheme.Unfocusable = moduleConfig.UString("colors.border.normal", colorsConfig.UString("border.normal", defaultColorTheme.BorderTheme.Unfocusable))
|
||
|
||
baseColors.CheckboxTheme.Checked = moduleConfig.UString("colors.checked", colorsConfig.UString("checked", defaultColorTheme.CheckboxTheme.Checked))
|
||
|
||
baseColors.RowTheme.EvenForeground = moduleConfig.UString("colors.rows.even", colorsConfig.UString("rows.even", defaultColorTheme.RowTheme.EvenForeground))
|
||
baseColors.RowTheme.OddForeground = moduleConfig.UString("colors.rows.odd", colorsConfig.UString("rows.odd", defaultColorTheme.RowTheme.OddForeground))
|
||
|
||
baseColors.TextTheme.Label = moduleConfig.UString("colors.label", colorsConfig.UString("label", defaultColorTheme.TextTheme.Label))
|
||
baseColors.TextTheme.Subheading = moduleConfig.UString("colors.subheading", colorsConfig.UString("subheading", defaultColorTheme.TextTheme.Subheading))
|
||
baseColors.TextTheme.Text = moduleConfig.UString("colors.text", colorsConfig.UString("text", defaultColorTheme.TextTheme.Text))
|
||
baseColors.TextTheme.Title = moduleConfig.UString("colors.title", colorsConfig.UString("title", defaultColorTheme.TextTheme.Title))
|
||
|
||
baseColors.WidgetTheme.Background = moduleConfig.UString("colors.background", colorsConfig.UString("background", defaultColorTheme.WidgetTheme.Background))
|
||
|
||
common := Common{
|
||
Colors: baseColors,
|
||
|
||
Module: Module{
|
||
Name: name,
|
||
Type: moduleConfig.UString("type", name),
|
||
},
|
||
|
||
PositionSettings: NewPositionSettingsFromYAML(name, moduleConfig),
|
||
|
||
Bordered: moduleConfig.UBool("border", true),
|
||
Config: moduleConfig,
|
||
Enabled: moduleConfig.UBool("enabled", false),
|
||
Focusable: moduleConfig.UBool("focusable", defaultFocusable),
|
||
LanguageTag: globalConfig.UString("wtf.language", defaultLanguageTag),
|
||
RefreshInterval: moduleConfig.UInt("refreshInterval", 300),
|
||
Title: moduleConfig.UString("title", defaultTitle),
|
||
|
||
focusChar: moduleConfig.UInt("focusChar", -1),
|
||
}
|
||
|
||
sigilsPath := "wtf.sigils"
|
||
common.Sigils.Checkbox.Checked = globalConfig.UString(sigilsPath+".checkbox.checked", "x")
|
||
common.Sigils.Checkbox.Unchecked = globalConfig.UString(sigilsPath+".checkbox.unchecked", " ")
|
||
common.Sigils.Paging.Normal = globalConfig.UString(sigilsPath+".paging.normal", globalConfig.UString("wtf.paging.pageSigil", "*"))
|
||
common.Sigils.Paging.Selected = globalConfig.UString(sigilsPath+".paging.select", globalConfig.UString("wtf.paging.selectedSigil", "_"))
|
||
|
||
return &common
|
||
}
|
||
|
||
/* -------------------- Exported Functions -------------------- */
|
||
|
||
func (common *Common) DefaultFocusedRowColor() string {
|
||
return fmt.Sprintf(
|
||
"%s:%s",
|
||
common.Colors.RowTheme.HighlightedForeground,
|
||
common.Colors.RowTheme.HighlightedBackground,
|
||
)
|
||
}
|
||
|
||
func (common *Common) DefaultRowColor() string {
|
||
return fmt.Sprintf(
|
||
"%s:%s",
|
||
common.Colors.RowTheme.EvenForeground,
|
||
common.Colors.RowTheme.EvenBackground,
|
||
)
|
||
}
|
||
|
||
// FocusChar returns the keyboard number assigned to the widget used to give onscreen
|
||
// focus to this widget, as a string. Focus characters can be a range between 1 and 9
|
||
func (common *Common) FocusChar() string {
|
||
if common.focusChar <= 0 {
|
||
return ""
|
||
}
|
||
|
||
if common.focusChar > 9 {
|
||
return ""
|
||
}
|
||
|
||
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 {
|
||
if idx%2 == 0 {
|
||
return common.Colors.RowTheme.EvenForeground
|
||
}
|
||
|
||
return common.Colors.RowTheme.OddForeground
|
||
}
|
||
|
||
func (common *Common) RightAlignFormat(width int) string {
|
||
borderOffset := 2
|
||
return fmt.Sprintf("%%%ds", width-borderOffset)
|
||
}
|
||
|
||
// PaginationMarker generates the pagination indicators that appear in the top-right corner
|
||
// of multisource widgets
|
||
func (common *Common) PaginationMarker(len, pos, width int) string {
|
||
sigils := ""
|
||
|
||
if len > 1 {
|
||
sigils = strings.Repeat(common.Sigils.Paging.Normal, pos)
|
||
sigils += common.Sigils.Paging.Selected
|
||
sigils += strings.Repeat(common.Sigils.Paging.Normal, len-1-pos)
|
||
|
||
sigils = "[lightblue]" + fmt.Sprintf(common.RightAlignFormat(width), sigils) + "[white]"
|
||
}
|
||
|
||
return sigils
|
||
}
|
||
|
||
// SetDocumentationPath is used to explicitly set the documentation path that should be opened
|
||
// when the key to open the documentation is pressed.
|
||
// Setting this is probably not necessary unless the module documentation is nested inside a
|
||
// documentation subdirectory in the /wtfutildocs repo, or the module here has a different
|
||
// name than the module's display name in the documentation (which ideally wouldn't be a thing).
|
||
func (common *Common) SetDocumentationPath(path string) {
|
||
common.DocPath = path
|
||
}
|
||
|
||
// Validations aggregates all the validations from all the sub-sections in Common into a
|
||
// single array of validations
|
||
func (common *Common) Validations() []Validatable {
|
||
validatables := []Validatable{}
|
||
|
||
for _, validation := range common.PositionSettings.Validations.validations {
|
||
validatables = append(validatables, validation)
|
||
}
|
||
|
||
return validatables
|
||
}
|