|
|
@ -9,10 +9,13 @@ import (
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/goodsign/monday"
|
|
|
|
"github.com/goodsign/monday"
|
|
|
|
|
|
|
|
"github.com/jeandeaual/go-locale"
|
|
|
|
"golang.org/x/text/language"
|
|
|
|
"golang.org/x/text/language"
|
|
|
|
"golang.org/x/text/message"
|
|
|
|
"golang.org/x/text/message"
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var cachedSystemLocale = ""
|
|
|
|
|
|
|
|
|
|
|
|
// Numericf produces a string from of the given number with give fixed precision
|
|
|
|
// Numericf produces a string from of the given number with give fixed precision
|
|
|
|
// in base 10 with thousands separators after every three orders of magnitude
|
|
|
|
// in base 10 with thousands separators after every three orders of magnitude
|
|
|
|
// using thousands and decimal separator according to LC_NUMERIC; defaulting "en".
|
|
|
|
// using thousands and decimal separator according to LC_NUMERIC; defaulting "en".
|
|
|
@ -31,58 +34,59 @@ func Monetaryf(value float64, precision int) string {
|
|
|
|
return f(value, precision, "LC_MONETARY", false)
|
|
|
|
return f(value, precision, "LC_MONETARY", false)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Attempt to determine the locale from the current environment. If usage is provided, treat it as the name of a LC_xxx environment variable.
|
|
|
|
// borrowed from go-locale/util.go
|
|
|
|
// LANGUAGE
|
|
|
|
func splitLocale(locale string) (string, string) {
|
|
|
|
// LC_ALL Will override the setting of all other LC_* variables.
|
|
|
|
// Remove the encoding, if present
|
|
|
|
// LC_MONETARY Sets the locale for the LC_MONETARY category.
|
|
|
|
formattedLocale := strings.Split(locale, ".")[0]
|
|
|
|
// LC_NUMERIC Sets the locale for the LC_NUMERIC category.
|
|
|
|
// Normalize by replacing the hyphens with underscores
|
|
|
|
// LC_TIME Sets the locale for the LC_TIME category.
|
|
|
|
formattedLocale = strings.Replace(formattedLocale, "-", "_", -1)
|
|
|
|
// LANG Used as a substitute for any unset LC_* variable. If LANG is unset, it will act as if set to "C"
|
|
|
|
|
|
|
|
// Local is language[_territory][.codeset] [@modifier]
|
|
|
|
// Split at the underscore
|
|
|
|
func DetectLocale(usage string) string {
|
|
|
|
split := strings.Split(formattedLocale, "_")
|
|
|
|
if lc, ok := os.LookupEnv("LANGUAGE"); ok {
|
|
|
|
language := split[0]
|
|
|
|
return lc
|
|
|
|
territory := ""
|
|
|
|
|
|
|
|
if len(split) > 1 {
|
|
|
|
|
|
|
|
territory = split[1]
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if lc, ok := os.LookupEnv("LC_ALL"); ok {
|
|
|
|
|
|
|
|
return lc
|
|
|
|
return language, territory
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// GetLocale returns the current locale as defined in IETF BCP 47 (e.g. "en-US").
|
|
|
|
|
|
|
|
// The envvar is provided this is checked first, before the platform-specific defaults.
|
|
|
|
|
|
|
|
func getLocale(envvar string) string {
|
|
|
|
|
|
|
|
userLocale := "en-US" // default language-REGION
|
|
|
|
|
|
|
|
// First try looking up envar directly
|
|
|
|
|
|
|
|
envlang, ok := os.LookupEnv(envvar)
|
|
|
|
|
|
|
|
if ok {
|
|
|
|
|
|
|
|
language, region := splitLocale(envlang)
|
|
|
|
|
|
|
|
userLocale = language
|
|
|
|
|
|
|
|
if len(region) > 0 {
|
|
|
|
|
|
|
|
userLocale = strings.Join([]string{language, region}, "-")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if usage != "" {
|
|
|
|
} else {
|
|
|
|
if lc, ok := os.LookupEnv(strings.ToUpper(usage)); ok {
|
|
|
|
// Then use (cached) system-specific locale
|
|
|
|
return lc
|
|
|
|
if cachedSystemLocale == "" {
|
|
|
|
|
|
|
|
if loc, err := locale.GetLocale(); err == nil {
|
|
|
|
|
|
|
|
userLocale = loc
|
|
|
|
|
|
|
|
cachedSystemLocale = loc
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
userLocale = cachedSystemLocale
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if lc, ok := os.LookupEnv("LANG"); ok {
|
|
|
|
|
|
|
|
return lc
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return "C"
|
|
|
|
return userLocale
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// func DetectLanguage(usage string) language.Tag {
|
|
|
|
// formatTimeExplicit formats the given time using the prescribed layout with the provided userLocale
|
|
|
|
// lc := DetectLocale(usage)
|
|
|
|
func formatTimeExplicit(time time.Time, layout string, userLocale string) string {
|
|
|
|
// if lc == "C" {
|
|
|
|
mondayLocale := monday.Locale(strings.Replace(userLocale, "-", "_", 1))
|
|
|
|
// lc = "en"
|
|
|
|
return monday.Format(time, layout, mondayLocale)
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
// return language.Make(lc)
|
|
|
|
|
|
|
|
// }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Locale is language[_territory][.codeset] [@modifier]
|
|
|
|
// FormatTime is a dropin replacement time.Format(layout) that uses system locale + LC_TIME
|
|
|
|
func FormatTime(time time.Time, layout string) string {
|
|
|
|
func FormatTime(time time.Time, layout string) string {
|
|
|
|
// Attempt to use the environment to determine monday.Locale
|
|
|
|
return formatTimeExplicit(time, layout, getLocale("LC_TIME"))
|
|
|
|
xxx := strings.Split(DetectLocale("LC_TIME"), ".")[0]
|
|
|
|
|
|
|
|
bits := strings.Split(xxx, "_")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Look for a supported Locale with default to en_US
|
|
|
|
|
|
|
|
var locale monday.Locale = monday.LocaleEnUS // default
|
|
|
|
|
|
|
|
if len(bits) == 2 {
|
|
|
|
|
|
|
|
lookFor := monday.Locale(strings.ToLower(bits[0]) + "_" + strings.ToUpper(bits[1]))
|
|
|
|
|
|
|
|
for _, v := range monday.ListLocales() {
|
|
|
|
|
|
|
|
if v == lookFor {
|
|
|
|
|
|
|
|
locale = v
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return monday.Format(time, layout, locale)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// f formats given value, with precision decimal places using thousands and decimal
|
|
|
|
// f formats given value, with precision decimal places using thousands and decimal
|
|
|
|