From 24f1286067440f44bf5fcb513831b7fa80715d88 Mon Sep 17 00:00:00 2001 From: Simon Roberts Date: Wed, 6 Oct 2021 19:04:38 +1100 Subject: [PATCH 1/6] Add github.com/goodsign/monday for locale-specific date formatting --- go.mod | 1 + go.sum | 2 + vendor/github.com/goodsign/monday/.gitignore | 24 + vendor/github.com/goodsign/monday/LICENCE | 9 + vendor/github.com/goodsign/monday/README.md | 161 +++++ .../github.com/goodsign/monday/automation.go | 345 +++++++++++ .../goodsign/monday/default_formats.go | 412 +++++++++++++ .../goodsign/monday/default_orders.go | 71 +++ vendor/github.com/goodsign/monday/doc.go | 38 ++ .../goodsign/monday/format_bg_bg.go | 55 ++ .../goodsign/monday/format_ca_es.go | 55 ++ .../goodsign/monday/format_common.go | 183 ++++++ .../goodsign/monday/format_cs_cz.go | 85 +++ .../goodsign/monday/format_da_dk.go | 55 ++ .../goodsign/monday/format_de_de.go | 55 ++ .../goodsign/monday/format_el_gr.go | 77 +++ .../goodsign/monday/format_en_gb.go | 55 ++ .../goodsign/monday/format_en_us.go | 55 ++ .../goodsign/monday/format_es_es.go | 55 ++ .../goodsign/monday/format_fi_fi.go | 70 +++ .../goodsign/monday/format_fr_fr.go | 55 ++ .../goodsign/monday/format_hu_hu.go | 55 ++ .../goodsign/monday/format_id_id.go | 55 ++ .../goodsign/monday/format_it_it.go | 55 ++ .../goodsign/monday/format_ja_jp.go | 95 +++ .../goodsign/monday/format_ko_kr.go | 94 +++ .../goodsign/monday/format_nb_no.go | 55 ++ .../goodsign/monday/format_nl_be.go | 55 ++ .../goodsign/monday/format_nn_no.go | 55 ++ .../goodsign/monday/format_pl_pl.go | 56 ++ .../goodsign/monday/format_pt_br.go | 55 ++ .../goodsign/monday/format_pt_pt.go | 72 +++ .../goodsign/monday/format_ro_RO.go | 55 ++ .../goodsign/monday/format_ru_ru.go | 85 +++ .../goodsign/monday/format_sl_si.go | 55 ++ .../goodsign/monday/format_sv_se.go | 55 ++ .../goodsign/monday/format_tr_tr.go | 55 ++ .../goodsign/monday/format_uk_ua.go | 85 +++ .../goodsign/monday/format_zh_cn.go | 75 +++ .../goodsign/monday/format_zh_hk.go | 55 ++ .../goodsign/monday/format_zh_tw.go | 55 ++ vendor/github.com/goodsign/monday/locale.go | 91 +++ vendor/github.com/goodsign/monday/monday.go | 563 ++++++++++++++++++ vendor/github.com/goodsign/monday/set.go | 67 +++ .../goodsign/monday/utils_layout.go | 92 +++ vendor/modules.txt | 3 + 46 files changed, 4011 insertions(+) create mode 100644 vendor/github.com/goodsign/monday/.gitignore create mode 100644 vendor/github.com/goodsign/monday/LICENCE create mode 100644 vendor/github.com/goodsign/monday/README.md create mode 100644 vendor/github.com/goodsign/monday/automation.go create mode 100644 vendor/github.com/goodsign/monday/default_formats.go create mode 100644 vendor/github.com/goodsign/monday/default_orders.go create mode 100644 vendor/github.com/goodsign/monday/doc.go create mode 100644 vendor/github.com/goodsign/monday/format_bg_bg.go create mode 100644 vendor/github.com/goodsign/monday/format_ca_es.go create mode 100644 vendor/github.com/goodsign/monday/format_common.go create mode 100644 vendor/github.com/goodsign/monday/format_cs_cz.go create mode 100644 vendor/github.com/goodsign/monday/format_da_dk.go create mode 100644 vendor/github.com/goodsign/monday/format_de_de.go create mode 100644 vendor/github.com/goodsign/monday/format_el_gr.go create mode 100644 vendor/github.com/goodsign/monday/format_en_gb.go create mode 100644 vendor/github.com/goodsign/monday/format_en_us.go create mode 100644 vendor/github.com/goodsign/monday/format_es_es.go create mode 100644 vendor/github.com/goodsign/monday/format_fi_fi.go create mode 100644 vendor/github.com/goodsign/monday/format_fr_fr.go create mode 100644 vendor/github.com/goodsign/monday/format_hu_hu.go create mode 100644 vendor/github.com/goodsign/monday/format_id_id.go create mode 100644 vendor/github.com/goodsign/monday/format_it_it.go create mode 100644 vendor/github.com/goodsign/monday/format_ja_jp.go create mode 100644 vendor/github.com/goodsign/monday/format_ko_kr.go create mode 100644 vendor/github.com/goodsign/monday/format_nb_no.go create mode 100644 vendor/github.com/goodsign/monday/format_nl_be.go create mode 100644 vendor/github.com/goodsign/monday/format_nn_no.go create mode 100644 vendor/github.com/goodsign/monday/format_pl_pl.go create mode 100644 vendor/github.com/goodsign/monday/format_pt_br.go create mode 100644 vendor/github.com/goodsign/monday/format_pt_pt.go create mode 100644 vendor/github.com/goodsign/monday/format_ro_RO.go create mode 100644 vendor/github.com/goodsign/monday/format_ru_ru.go create mode 100644 vendor/github.com/goodsign/monday/format_sl_si.go create mode 100644 vendor/github.com/goodsign/monday/format_sv_se.go create mode 100644 vendor/github.com/goodsign/monday/format_tr_tr.go create mode 100644 vendor/github.com/goodsign/monday/format_uk_ua.go create mode 100644 vendor/github.com/goodsign/monday/format_zh_cn.go create mode 100644 vendor/github.com/goodsign/monday/format_zh_hk.go create mode 100644 vendor/github.com/goodsign/monday/format_zh_tw.go create mode 100644 vendor/github.com/goodsign/monday/locale.go create mode 100644 vendor/github.com/goodsign/monday/monday.go create mode 100644 vendor/github.com/goodsign/monday/set.go create mode 100644 vendor/github.com/goodsign/monday/utils_layout.go diff --git a/go.mod b/go.mod index 82e2586..06fa77d 100644 --- a/go.mod +++ b/go.mod @@ -10,6 +10,7 @@ require ( github.com/fatih/color v1.13.0 github.com/gen2brain/beeep v0.0.0-20210529141713-5586760f0cc1 github.com/gliderlabs/ssh v0.3.3 + github.com/goodsign/monday v1.0.0 github.com/maruel/panicparse v1.6.1 github.com/mattn/go-runewidth v0.0.13 github.com/miguelmota/go-coinmarketcap v0.1.8 diff --git a/go.sum b/go.sum index 681329c..8da5023 100644 --- a/go.sum +++ b/go.sum @@ -129,6 +129,8 @@ github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM= github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= +github.com/goodsign/monday v1.0.0 h1:Yyk/s/WgudMbAJN6UWSU5xAs8jtNewfqtVblAlw0yoc= +github.com/goodsign/monday v1.0.0/go.mod h1:r4T4breXpoFwspQNM+u2sLxJb2zyTaxVGqUfTBjWOu8= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= diff --git a/vendor/github.com/goodsign/monday/.gitignore b/vendor/github.com/goodsign/monday/.gitignore new file mode 100644 index 0000000..d390cf1 --- /dev/null +++ b/vendor/github.com/goodsign/monday/.gitignore @@ -0,0 +1,24 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe +/monday.iml +/.idea/ diff --git a/vendor/github.com/goodsign/monday/LICENCE b/vendor/github.com/goodsign/monday/LICENCE new file mode 100644 index 0000000..ac18870 --- /dev/null +++ b/vendor/github.com/goodsign/monday/LICENCE @@ -0,0 +1,9 @@ +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES +OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT +SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT +OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR +TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, +EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/vendor/github.com/goodsign/monday/README.md b/vendor/github.com/goodsign/monday/README.md new file mode 100644 index 0000000..f212254 --- /dev/null +++ b/vendor/github.com/goodsign/monday/README.md @@ -0,0 +1,161 @@ +Description +==== + +Monday is a minimalistic translator for month and day of week names in time.Date objects. Supports 20+ different locales. +Written in pure [Go](http://golang.org). + +![Go](https://github.com/goodsign/monday/workflows/Go/badge.svg) + +Installing +==== + +``` +go get github.com/goodsign/monday +``` + +Usage +==== + +Format +--------------------- + +Given that you already use [time.Format](http://golang.org/pkg/time/#Time.Format) somewhere in your code, +to translate your output you should import monday and replace + +```go + yourTime.Format(yourLayout) +``` + +with + +```go + // Change LocaleEnUS to the locale you want to use for translation + monday.Format(yourTime, yourLayout, monday.LocaleEnUS) +``` + +Parse +--------------------- + +Given that you already use [time.ParseInLocation](http://golang.org/pkg/time/#ParseInLocation) somewhere in your code, +to parse input string in a different language you should import monday and replace + +```go + time.ParseInLocation(yourLayout, yourString, yourLocation) +``` + +with + +```go + // Change LocaleEnUS to the locale you want to use for translation + monday.ParseInLocation(yourLayout, yourString, yourLocation, monday.LocaleEnUS) +``` + +Predefined formats +--------------------- + +Monday declares some predefined formats: Full, Long, Medium, Short, DateTime formats for each locale. E.g. to get +short format for any locale you can use map: + +```go +monday.ShortFormatsByLocale[locale] +``` + +Usage notes +----------- + +**Monday** is not an alternative to standard **time** package. It is a temporary solution to use while +the internationalization features are not ready. + +That's why **monday** doesn't create any additional parsing algorithms, layout identifiers. It is just +a wrapper for time.Format and time.ParseInLocation and uses all the same layout IDs, constants, etc. + +So, the changes you need to temporarily switch to **monday** (while the internationalization features are being developed) +are minimal: you preserve your layout, your time object, your parsed date string formats and the only change is +the func call itself. + +Locales +---- + +Supported locales are listed in **locale.go** file. + +``` +const ( + LocaleEnUS = "en_US" // English (United States) + LocaleEnGB = "en_GB" // English (United Kingdom) + LocaleDaDK = "da_DK" // Danish (Denmark) + LocaleNlBE = "nl_BE" // Dutch (Belgium) + LocaleNlNL = "nl_NL" // Dutch (Netherlands) + LocaleFiFI = "fi_FI" // Finnish (Finland) + LocaleFrFR = "fr_FR" // French (France) + LocaleFrCA = "fr_CA" // French (Canada) + LocaleDeDE = "de_DE" // German (Germany) + LocaleHuHU = "hu_HU" // Hungarian (Hungary) + LocaleItIT = "it_IT" // Italian (Italy) + LocaleNnNO = "nn_NO" // Norwegian Nynorsk (Norway) + LocaleNbNO = "nb_NO" // Norwegian Bokmål (Norway) + LocalePlPL = "pl_PL" // Polish (Poland) + LocalePtPT = "pt_PT" // Portuguese (Portugal) + LocalePtBR = "pt_BR" // Portuguese (Brazil) + LocaleRoRO = "ro_RO" // Romanian (Romania) + LocaleRuRU = "ru_RU" // Russian (Russia) + LocaleEsES = "es_ES" // Spanish (Spain) + LocaleCaES = "ca_ES" // Catalan (Spain) + LocaleSvSE = "sv_SE" // Swedish (Sweden) + LocaleTrTR = "tr_TR" // Turkish (Turkey) + LocaleUkUA = "uk_UA" // Ukrainian (Ukraine) + LocaleBgBG = "bg_BG" // Bulgarian (Bulgaria) + LocaleZhCN = "zh_CN" // Chinese (Mainland) + LocaleZhTW = "zh_TW" // Chinese (Taiwan) + LocaleZhHK = "zh_HK" // Chinese (Hong Kong) + LocaleKoKR = "ko_KR" // Korean (Korea) + LocaleJaJP = "ja_JP" // Japanese (Japan) + LocaleElGR = "el_GR" // Greek (Greece) + LocaleIdID = "id_ID" // Indonesian (Indonesia) + LocaleFrGP = "fr_GP" // French (Guadeloupe) + LocaleFrLU = "fr_LU" // French (Luxembourg) + LocaleFrMQ = "fr_MQ" // French (Martinique) + LocaleFrGF = "fr_GF" // French (French Guiana) + LocaleFrGF = "fr_RE" // French (Reunion) + LocaleCsCZ = "cs_CZ" // Czech (Czech Republic) + LocaleSlSI = "sl_SI" // Slovenian (Slovenia) +) +``` + +LocaleDetector +==== + +```go + var timeLocaleDetector *monday.LocaleDetector = monday.NewLocaleDetector() + dateTime, err := timeLocaleDetector.Parse(layout,datestr) +``` +parses datetime with **unknown** locale (for now - layout must be defined, as for time.Parse()) + +useful for text parsing tools/crawlers (f.e.: rss-feeds crawler) + +TODO: + * make LocaleDetector insensitive to whitespaces count + +Thread-safety +==== + +**Monday** initializes all its data once in the **init** func and then uses only +func calls and local vars. Thus, it's thread-safe and doesn't need any mutexes to be +used with. + +Monday Licence +========== + +The **Monday** library is released under the [BSD Licence](http://opensource.org/licenses/bsd-license.php) + +[LICENCE file](https://github.com/goodsign/monday/blob/master/LICENCE) + +Thanks +========== + +* [Martin Angers](https://github.com/PuerkitoBio) +* Andrey Mirtchovski +* [mikespook](https://github.com/mikespook) +* [Luis Azevedo](https://github.com/braceta) +* [imikod](https://github.com/imikod) +* [Renato Serra](https://github.com/RenatoSerra22) +* [Zachary Stewart](https://github.com/ztstewart) diff --git a/vendor/github.com/goodsign/monday/automation.go b/vendor/github.com/goodsign/monday/automation.go new file mode 100644 index 0000000..db04c50 --- /dev/null +++ b/vendor/github.com/goodsign/monday/automation.go @@ -0,0 +1,345 @@ +package monday + +import ( + "errors" + "fmt" + "regexp" + "strconv" + "strings" + "text/scanner" + "time" +) + +var ( + wordsRx = regexp.MustCompile("(\\p{L}+)") + debugLayoutDef = false +) + +// An InvalidTypeError indicates that data was parsed incorrectly as a result +// of a type mismatch. +type InvalidTypeError struct { + error +} + +// An InvalidLengthError is returned when an item's length was longer or +// shorter than expected for a particular token. +type InvalidLengthError struct { + error +} + +// NewInvalidTypeError instantiates an InvalidTypeError. +func NewInvalidTypeError() InvalidTypeError { + return InvalidTypeError{error: errors.New("invalid type for token")} +} + +// NewInvalidLengthError instantiates an InvalidLengthError. +func NewInvalidLengthError() InvalidLengthError { + return InvalidLengthError{error: errors.New("invalid length for token")} +} + +type layoutSpanI interface { + scanInt(s *scanner.Scanner) (int, error) + scanString(s *scanner.Scanner) (string, error) + isString() bool + isDelimiter() bool +} + +type lengthLimitSpan struct { + minLength int + maxLength int +} + +func (lls lengthLimitSpan) scanInt(s *scanner.Scanner) (int, error) { + return -1, NewInvalidTypeError() +} + +func (lls lengthLimitSpan) scanString(s *scanner.Scanner) (string, error) { + return "", NewInvalidTypeError() +} + +func (lls lengthLimitSpan) isString() bool { return false } +func (lls lengthLimitSpan) isDelimiter() bool { return false } + +func initLengthLimitSpan(min, max int) lengthLimitSpan { + return lengthLimitSpan{ + minLength: min, + maxLength: max, + } +} + +type limitedStringSpan struct { + lengthLimitSpan +} + +func initLimitedStringSpan(minLength, maxLength int) limitedStringSpan { + return limitedStringSpan{lengthLimitSpan: initLengthLimitSpan(minLength, maxLength)} +} + +func (lss limitedStringSpan) scanString(s *scanner.Scanner) (string, error) { + tok := s.Scan() + if tok != scanner.EOF && tok == -2 { + return s.TokenText(), nil + } + return "", NewInvalidTypeError() +} + +func (lss limitedStringSpan) isString() bool { return true } +func (lss limitedStringSpan) String() string { + return fmt.Sprintf("[limitedStringSpan:%v]", lss.lengthLimitSpan) +} + +type rangeIntSpan struct { + lengthLimitSpan + min int + max int +} + +func initRangeIntSpan(minValue, maxValue, minLength, maxLength int) rangeIntSpan { + return rangeIntSpan{ + lengthLimitSpan: initLengthLimitSpan(minLength, maxLength), + min: minValue, + max: maxValue, + } +} + +func (rs rangeIntSpan) scanInt(s *scanner.Scanner) (int, error) { + var tok = s.Scan() + var negative bool + if tok == 45 { + negative = true + if debugLayoutDef { + fmt.Printf("scan negative:'%s'\n", s.TokenText()) + } + tok = s.Scan() + } else if tok == 43 { // positive + tok = s.Scan() + } + if tok == -3 { + str := s.TokenText() + i, err := strconv.Atoi(str) + if err != nil { + return 0, err + } + if negative { + i = i * -1 + } + return i, nil + } + + if debugLayoutDef { + fmt.Printf("invalid tok: %v '%s'\n", tok, s.TokenText()) + } + + return 0, NewInvalidTypeError() +} + +func (rs rangeIntSpan) String() string { + return fmt.Sprintf("[rangeIntSpan:%v]", rs.lengthLimitSpan) +} + +type delimiterSpan struct { + lengthLimitSpan + character string +} + +func initDelimiterSpan(character string, minLength, maxLength int) delimiterSpan { + return delimiterSpan{ + lengthLimitSpan: initLengthLimitSpan(minLength, maxLength), + character: character, + } +} + +func (ds delimiterSpan) scanString(s *scanner.Scanner) (string, error) { + tok := s.Scan() + if tok != scanner.EOF && tok != -2 && tok != 45 && tok != -3 { + return s.TokenText(), nil + } + if debugLayoutDef { + fmt.Printf("expected tok:=!(-2,-3,45), received:%d ('%s')\n", tok, s.TokenText()) + } + + return "", NewInvalidTypeError() +} + +func (ds delimiterSpan) isString() bool { return false } +func (ds delimiterSpan) isDelimiter() bool { return true } +func (ds delimiterSpan) String() string { + return fmt.Sprintf("[delimiterSpan '%s':%v]", ds.character, ds.lengthLimitSpan) +} + +type layoutDef struct { + spans []layoutSpanI + errorPosition int +} + +func (ld *layoutDef) validate(value string) bool { + s := &scanner.Scanner{} + s.Init(strings.NewReader(value)) + s.Whitespace = 0 + for _, span := range ld.spans { + if span.isString() || span.isDelimiter() { + if _, err := span.scanString(s); err != nil { + ld.errorPosition = s.Pos().Offset + if debugLayoutDef { + fmt.Printf("error at pos: %d: %s (span=%+v) - expected string or delimiter\n", s.Pos().Offset, err.Error(), span) + } + return false + } + } else if _, err := span.scanInt(s); err != nil { + if debugLayoutDef { + fmt.Printf("error at pos: %d: %s (span=%+v) - expected integer\n", s.Pos().Offset, err.Error(), span) + } + ld.errorPosition = s.Pos().Offset + return false + } + } + ld.errorPosition = s.Pos().Offset + return s.Pos().Offset == len(value) +} + +// A LocaleDetector parses time.Time values by using various heuristics and +// techniques to determine which locale should be used to parse the +// time.Time value. As not all possible locales and formats are supported, +// this process can be somewhat lossy and inaccurate. +type LocaleDetector struct { + localeMap map[string]*set + lastLocale Locale + layoutsMap map[string]layoutDef + lastErrorPosition int +} + +func (ld *LocaleDetector) prepareLayout(layout string) layoutDef { + s := scanner.Scanner{} + s.Init(strings.NewReader(layout)) + s.Whitespace = 0 + result := make([]layoutSpanI, 0) + var tok rune + // var pos int = 0 + var span layoutSpanI + var sign bool + // var neg bool = false + for tok != scanner.EOF { + tok = s.Scan() + switch tok { + case -2: // text + span = initLimitedStringSpan(1, -1) + case -3: // digit + span = initRangeIntSpan(-1, -1, 1, -1) + if sign { + sign = false + } + case 45: // negative sign + sign = true + // neg = s.TokenText() == "-" + continue + case 43: // positive sign + sign = true + continue + case scanner.EOF: + continue + default: // fixed character + span = initDelimiterSpan(s.TokenText(), 1, 1) + } + result = append(result, span) + // length := s.Pos().Offset - pos + // pos = s.Pos().Offset + // fmt.Printf("tok'%s' [%d %d] length=%d\n", s.TokenText(), pos, s.Pos().Offset, length) + + } + if debugLayoutDef { + fmt.Printf("layout:'%s'\n", layout) + fmt.Printf("layout:%v\n", result) + } + ret := layoutDef{spans: result} + ld.layoutsMap[layout] = ret + return ret +} + +func (ld *LocaleDetector) validateValue(layout string, value string) bool { + l, ok := ld.layoutsMap[layout] + if !ok { + l = ld.prepareLayout(layout) + } + result := l.validate(value) + ld.lastErrorPosition = l.errorPosition + return result +} + +func (ld *LocaleDetector) errorPosition() int { return ld.lastErrorPosition } + +func (ld *LocaleDetector) addWords(words []string, v Locale) { + for _, w := range words { + l := strings.ToLower(w) + if _, ok := ld.localeMap[w]; !ok { + ld.localeMap[w] = newSet(v) + if l != w { + ld.localeMap[l] = newSet(v) + } + } else { + ld.localeMap[w].Add(v) + if l != w { + ld.localeMap[l].Add(v) + } + } + } +} + +// NewLocaleDetector instances a LocaleDetector instance. +func NewLocaleDetector() *LocaleDetector { + ld := &LocaleDetector{localeMap: make(map[string]*set), lastLocale: LocaleEnGB, layoutsMap: make(map[string]layoutDef)} + for _, v := range ListLocales() { + days := GetShortDays(v) + ld.addWords(days, v) + days = GetLongDays(v) + ld.addWords(days, v) + months := GetShortMonths(v) + ld.addWords(months, v) + months = GetLongMonths(v) + ld.addWords(months, v) + } + return ld +} + +// Parse will attempt to parse a time.Time struct from a layout (format) and a +// value to parse from. +// +// If no locale can be determined, this method will return an error and an +// empty time object. +func (ld *LocaleDetector) Parse(layout, value string) (time.Time, error) { + if ld.validateValue(layout, value) { + ld.lastLocale = ld.detectLocale(value) + return ParseInLocation(layout, value, time.UTC, ld.lastLocale) + } + return time.Time{}, &time.ParseError{ + Value: value, + Layout: layout, + Message: fmt.Sprintf("'%s' not matches to '%s' last error position = %d\n", value, layout, ld.lastErrorPosition), + } +} + +func (ld *LocaleDetector) detectLocale(value string) Locale { + localesMap := make(map[Locale]int) + for _, v := range wordsRx.FindAllStringSubmatchIndex(value, -1) { + word := strings.ToLower(value[v[0]:v[1]]) + + if localesSet, ok := ld.localeMap[word]; ok { + localesSet.Each(func(loc Locale) bool { + if _, ok := localesMap[loc]; !ok { + localesMap[loc] = 1 + } else { + localesMap[loc]++ + } + return true + }) + } + } + var result Locale = LocaleEnUS + frequency := 0 + for key, counter := range localesMap { + if counter > frequency { + frequency = counter + result = key + } + } + return result +} diff --git a/vendor/github.com/goodsign/monday/default_formats.go b/vendor/github.com/goodsign/monday/default_formats.go new file mode 100644 index 0000000..8f40a0b --- /dev/null +++ b/vendor/github.com/goodsign/monday/default_formats.go @@ -0,0 +1,412 @@ +package monday + +// Default date formats by country. +// Mostly taken from http://en.wikipedia.org/wiki/Date_format_by_country +const ( + DefaultFormatEnUS = "01/02/06" + + DefaultFormatEnUSFull = "Monday, January 2, 2006" // English (United States) + DefaultFormatEnUSLong = "January 2, 2006" + DefaultFormatEnUSMedium = "Jan 02, 2006" + DefaultFormatEnUSShort = "1/2/06" + DefaultFormatEnUSDateTime = "1/2/06 3:04 PM" + + DefaultFormatEnGBFull = "Monday, 2 January 2006" // English (United Kingdom) + DefaultFormatEnGBLong = "2 January 2006" + DefaultFormatEnGBMedium = "02 Jan 2006" + DefaultFormatEnGBShort = "02/01/2006" + DefaultFormatEnGBDateTime = "02/01/2006 15:04" + + DefaultFormatDaDKFull = "Monday den 2. January 2006" // Danish (Denmark) + DefaultFormatDaDKLong = "2. Jan 2006" + DefaultFormatDaDKMedium = "02/01/2006" + DefaultFormatDaDKShort = "02/01/06" + DefaultFormatDaDKDateTime = "02/01/2006 15.04" + + DefaultFormatNlBEFull = "Monday 2 January 2006" // Dutch (Belgium) + DefaultFormatNlBELong = "2 January 2006" + DefaultFormatNlBEMedium = "02-Jan-2006" + DefaultFormatNlBEShort = "2/01/06" + DefaultFormatNlBEDateTime = "2/01/06 15:04" + + DefaultFormatNlNLFull = "Monday 2 January 2006" // Dutch (Netherlands) + DefaultFormatNlNLLong = "2 January 2006" + DefaultFormatNlNLMedium = "02 Jan 2006" + DefaultFormatNlNLShort = "02-01-06" + DefaultFormatNlNLDateTime = "02-01-06 15:04" + + DefaultFormatFiFIFull = "Monday 2. January 2006" // Finnish (Finland) + DefaultFormatFiFILong = "2. January 2006" + DefaultFormatFiFIMedium = "02.1.2006" + DefaultFormatFiFIShort = "02.1.2006" + DefaultFormatFiFIDateTime = "02.1.2006 15.04" + + DefaultFormatFrFRFull = "Monday 2 January 2006" // French (France) + DefaultFormatFrFRLong = "2 January 2006" + DefaultFormatFrFRMedium = "02 Jan 2006" + DefaultFormatFrFRShort = "02/01/2006" + DefaultFormatFrFRDateTime = "02/01/2006 15:04" + + DefaultFormatFrCAFull = "Monday 2 January 2006" // French (Canada) + DefaultFormatFrCALong = "2 January 2006" + DefaultFormatFrCAMedium = "2006-01-02" + DefaultFormatFrCAShort = "06-01-02" + DefaultFormatFrCADateTime = "06-01-02 15:04" + + DefaultFormatFrGPFull = "Monday 2 January 2006" // French (Canada) + DefaultFormatFrGPLong = "2 January 2006" + DefaultFormatFrGPMedium = "2006-01-02" + DefaultFormatFrGPShort = "06-01-02" + DefaultFormatFrGPDateTime = "06-01-02 15:04" + + DefaultFormatFrLUFull = "Monday 2 January 2006" // French (Luxembourg) + DefaultFormatFrLULong = "2 January 2006" + DefaultFormatFrLUMedium = "2006-01-02" + DefaultFormatFrLUShort = "06-01-02" + DefaultFormatFrLUDateTime = "06-01-02 15:04" + + DefaultFormatFrMQFull = "Monday 2 January 2006" // French (Martinique) + DefaultFormatFrMQLong = "2 January 2006" + DefaultFormatFrMQMedium = "2006-01-02" + DefaultFormatFrMQShort = "06-01-02" + DefaultFormatFrMQDateTime = "06-01-02 15:04" + + DefaultFormatFrGFFull = "Monday 2 January 2006" // French (French Guiana) + DefaultFormatFrGFLong = "2 January 2006" + DefaultFormatFrGFMedium = "2006-01-02" + DefaultFormatFrGFShort = "06-01-02" + DefaultFormatFrGFDateTime = "06-01-02 15:04" + + DefaultFormatFrREFull = "Monday 2 January 2006" // French (Reunion) + DefaultFormatFrRELong = "2 January 2006" + DefaultFormatFrREMedium = "2006-01-02" + DefaultFormatFrREShort = "06-01-02" + DefaultFormatFrREDateTime = "06-01-02 15:04" + + DefaultFormatDeDEFull = "Monday, 2. January 2006" // German (Germany) + DefaultFormatDeDELong = "2. January 2006" + DefaultFormatDeDEMedium = "02.01.2006" + DefaultFormatDeDEShort = "02.01.06" + DefaultFormatDeDEDateTime = "02.01.06 15:04" + + DefaultFormatHuHUFull = "2006. January 2., Monday" // Hungarian (Hungary) + DefaultFormatHuHULong = "2006. January 2." + DefaultFormatHuHUMedium = "2006.01.02." + DefaultFormatHuHUShort = "2006.01.02." + DefaultFormatHuHUDateTime = "2006.01.02. 15:04" + + DefaultFormatItITFull = "Monday 2 January 2006" // Italian (Italy) + DefaultFormatItITLong = "2 January 2006" + DefaultFormatItITMedium = "02/Jan/2006" + DefaultFormatItITShort = "02/01/06" + DefaultFormatItITDateTime = "02/01/06 15:04" + + DefaultFormatNnNOFull = "Monday 2. January 2006" // Norwegian Nynorsk (Norway) + DefaultFormatNnNOLong = "2. January 2006" + DefaultFormatNnNOMedium = "02. Jan 2006" + DefaultFormatNnNOShort = "02.01.06" + DefaultFormatNnNODateTime = "02.01.06 15:04" + + DefaultFormatNbNOFull = "Monday 2. January 2006" // Norwegian Bokmål (Norway) + DefaultFormatNbNOLong = "2. January 2006" + DefaultFormatNbNOMedium = "02. Jan 2006" + DefaultFormatNbNOShort = "02.01.06" + DefaultFormatNbNODateTime = "15:04 02.01.06" + + DefaultFormatPtPTFull = "Monday, 2 de January de 2006" // Portuguese (Portugal) + DefaultFormatPtPTLong = "2 de January de 2006" + DefaultFormatPtPTMedium = "02/01/2006" + DefaultFormatPtPTShort = "02/01/06" + DefaultFormatPtPTDateTime = "02/01/06, 15:04" + + DefaultFormatPtBRFull = "Monday, 2 de January de 2006" // Portuguese (Brazil) + DefaultFormatPtBRLong = "02 de January de 2006" + DefaultFormatPtBRMedium = "02/01/2006" + DefaultFormatPtBRShort = "02/01/06" + DefaultFormatPtBRDateTime = "02/01/06, 15:04" + + DefaultFormatRoROFull = "Monday, 02 January 2006" // Romanian (Romania) + DefaultFormatRoROLong = "02 January 2006" + DefaultFormatRoROMedium = "02.01.2006" + DefaultFormatRoROShort = "02.01.2006" + DefaultFormatRoRODateTime = "02.01.06, 15:04" + + DefaultFormatRuRUFull = "Monday, 2 January 2006 г." // Russian (Russia) + DefaultFormatRuRULong = "2 January 2006 г." + DefaultFormatRuRUMedium = "02 Jan 2006 г." + DefaultFormatRuRUShort = "02.01.06" + DefaultFormatRuRUDateTime = "02.01.06, 15:04" + + DefaultFormatEsESFull = "Monday, 2 de January de 2006" // Spanish (Spain) + DefaultFormatEsESLong = "2 de January de 2006" + DefaultFormatEsESMedium = "02/01/2006" + DefaultFormatEsESShort = "02/01/06" + DefaultFormatEsESDateTime = "02/01/06 15:04" + + DefaultFormatCaESFull = "Monday, 2 de January de 2006" // Spanish (Spain) + DefaultFormatCaESLong = "2 de January de 2006" + DefaultFormatCaESMedium = "02/01/2006" + DefaultFormatCaESShort = "02/01/06" + DefaultFormatCaESDateTime = "02/01/06 15:04" + + DefaultFormatSvSEFull = "Mondayen den 2:e January 2006" // Swedish (Sweden) + DefaultFormatSvSELong = "2 January 2006" + DefaultFormatSvSEMedium = "2 Jan 2006" + DefaultFormatSvSEShort = "2006-01-02" + DefaultFormatSvSEDateTime = "2006-01-02 15:04" + + DefaultFormatTrTRFull = "2 January 2006 Monday" // Turkish (Turkey) + DefaultFormatTrTRLong = "2 January 2006" + DefaultFormatTrTRMedium = "2 Jan 2006" + DefaultFormatTrTRShort = "2.01.2006" + DefaultFormatTrTRDateTime = "2.01.2006 15:04" + + DefaultFormatUkUAFull = "Monday, 2 January 2006 р." // Ukrainian (Ukraine) + DefaultFormatUkUALong = "2 January 2006 р." + DefaultFormatUkUAMedium = "02 Jan 2006 р." + DefaultFormatUkUAShort = "02.01.06" + DefaultFormatUkUADateTime = "02.01.06, 15:04" + + DefaultFormatBgBGFull = "Monday, 2 January 2006" // Bulgarian (Bulgaria) + DefaultFormatBgBGLong = "2 January 2006" + DefaultFormatBgBGMedium = "2 Jan 2006" + DefaultFormatBgBGShort = "2.01.2006" + DefaultFormatBgBGDateTime = "2.01.2006 15:04" + + DefaultFormatZhCNFull = "2006年1月2日 Monday" // Chinese (Mainland) + DefaultFormatZhCNLong = "2006年1月2日" + DefaultFormatZhCNMedium = "2006-01-02" + DefaultFormatZhCNShort = "2006/1/2" + DefaultFormatZhCNDateTime = "2006-01-02 15:04" + + DefaultFormatZhTWFull = "2006年1月2日 Monday" // Chinese (Taiwan) + DefaultFormatZhTWLong = "2006年1月2日" + DefaultFormatZhTWMedium = "2006-01-02" + DefaultFormatZhTWShort = "2006/1/2" + DefaultFormatZhTWDateTime = "2006-01-02 15:04" + + DefaultFormatZhHKFull = "2006年1月2日 Monday" // Chinese (Hong Kong) + DefaultFormatZhHKLong = "2006年1月2日" + DefaultFormatZhHKMedium = "2006-01-02" + DefaultFormatZhHKShort = "2006/1/2" + DefaultFormatZhHKDateTime = "2006-01-02 15:04" + + DefaultFormatKoKRFull = "2006년1월2일 월요일" // Korean (Korea) + DefaultFormatKoKRLong = "2006년1월2일" + DefaultFormatKoKRMedium = "2006-01-02" + DefaultFormatKoKRShort = "2006/1/2" + DefaultFormatKoKRDateTime = "2006-01-02 15:04" + + DefaultFormatJaJPFull = "2006年1月2日 Monday" // Japanese (Japan) + DefaultFormatJaJPLong = "2006年1月2日" + DefaultFormatJaJPMedium = "2006/01/02" + DefaultFormatJaJPShort = "2006/1/2" + DefaultFormatJaJPDateTime = "2006/01/02 15:04" + + DefaultFormatElGRFull = "Monday, 2 January 2006" // Greek (Greece) + DefaultFormatElGRLong = "2 January 2006" + DefaultFormatElGRMedium = "2 Jan 2006" + DefaultFormatElGRShort = "02/01/06" + DefaultFormatElGRDateTime = "02/01/06 15:04" + + DefaultFormatCsCZFull = "Monday, 2. January 2006" // Czech (Czech Republic) + DefaultFormatCsCZLong = "2. January 2006" + DefaultFormatCsCZMedium = "02 Jan 2006" + DefaultFormatCsCZShort = "02/01/2006" + DefaultFormatCsCZDateTime = "02/01/2006 15:04" +) + +// FullFormatsByLocale maps locales to the'full' date formats for all +// supported locales. +var FullFormatsByLocale = map[Locale]string{ + LocaleEnUS: DefaultFormatEnUSFull, + LocaleEnGB: DefaultFormatEnGBFull, + LocaleDaDK: DefaultFormatDaDKFull, + LocaleNlBE: DefaultFormatNlBEFull, + LocaleNlNL: DefaultFormatNlNLFull, + LocaleFiFI: DefaultFormatFiFIFull, + LocaleFrFR: DefaultFormatFrFRFull, + LocaleFrCA: DefaultFormatFrCAFull, + LocaleFrGP: DefaultFormatFrGPFull, + LocaleFrLU: DefaultFormatFrLUFull, + LocaleFrMQ: DefaultFormatFrMQFull, + LocaleFrGF: DefaultFormatFrGFFull, + LocaleFrRE: DefaultFormatFrREFull, + LocaleDeDE: DefaultFormatDeDEFull, + LocaleHuHU: DefaultFormatHuHUFull, + LocaleItIT: DefaultFormatItITFull, + LocaleNnNO: DefaultFormatNnNOFull, + LocaleNbNO: DefaultFormatNbNOFull, + LocalePtPT: DefaultFormatPtPTFull, + LocalePtBR: DefaultFormatPtBRFull, + LocaleRoRO: DefaultFormatRoROFull, + LocaleRuRU: DefaultFormatRuRUFull, + LocaleEsES: DefaultFormatEsESFull, + LocaleCaES: DefaultFormatCaESFull, + LocaleSvSE: DefaultFormatSvSEFull, + LocaleTrTR: DefaultFormatTrTRFull, + LocaleBgBG: DefaultFormatBgBGFull, + LocaleZhCN: DefaultFormatZhCNFull, + LocaleZhTW: DefaultFormatZhTWFull, + LocaleZhHK: DefaultFormatZhHKFull, + LocaleKoKR: DefaultFormatKoKRFull, + LocaleJaJP: DefaultFormatJaJPFull, + LocaleElGR: DefaultFormatElGRFull, + LocaleCsCZ: DefaultFormatCsCZFull, +} + +// LongFormatsByLocale maps locales to the 'long' date formats for all +// supported locales. +var LongFormatsByLocale = map[Locale]string{ + LocaleEnUS: DefaultFormatEnUSLong, + LocaleEnGB: DefaultFormatEnGBLong, + LocaleDaDK: DefaultFormatDaDKLong, + LocaleNlBE: DefaultFormatNlBELong, + LocaleNlNL: DefaultFormatNlNLLong, + LocaleFiFI: DefaultFormatFiFILong, + LocaleFrFR: DefaultFormatFrFRLong, + LocaleFrCA: DefaultFormatFrCALong, + LocaleFrGP: DefaultFormatFrGPLong, + LocaleFrLU: DefaultFormatFrLULong, + LocaleFrMQ: DefaultFormatFrMQLong, + LocaleFrRE: DefaultFormatFrRELong, + LocaleFrGF: DefaultFormatFrGFLong, + LocaleDeDE: DefaultFormatDeDELong, + LocaleHuHU: DefaultFormatHuHULong, + LocaleItIT: DefaultFormatItITLong, + LocaleNnNO: DefaultFormatNnNOLong, + LocaleNbNO: DefaultFormatNbNOLong, + LocalePtPT: DefaultFormatPtPTLong, + LocalePtBR: DefaultFormatPtBRLong, + LocaleRoRO: DefaultFormatRoROLong, + LocaleRuRU: DefaultFormatRuRULong, + LocaleEsES: DefaultFormatEsESLong, + LocaleCaES: DefaultFormatCaESLong, + LocaleSvSE: DefaultFormatSvSELong, + LocaleTrTR: DefaultFormatTrTRLong, + LocaleBgBG: DefaultFormatBgBGLong, + LocaleZhCN: DefaultFormatZhCNLong, + LocaleZhTW: DefaultFormatZhTWLong, + LocaleZhHK: DefaultFormatZhHKLong, + LocaleKoKR: DefaultFormatKoKRLong, + LocaleJaJP: DefaultFormatJaJPLong, + LocaleElGR: DefaultFormatElGRLong, + LocaleCsCZ: DefaultFormatCsCZLong, +} + +// MediumFormatsByLocale maps locales to the 'medium' date formats for all +// supported locales. +var MediumFormatsByLocale = map[Locale]string{ + LocaleEnUS: DefaultFormatEnUSMedium, + LocaleEnGB: DefaultFormatEnGBMedium, + LocaleDaDK: DefaultFormatDaDKMedium, + LocaleNlBE: DefaultFormatNlBEMedium, + LocaleNlNL: DefaultFormatNlNLMedium, + LocaleFiFI: DefaultFormatFiFIMedium, + LocaleFrFR: DefaultFormatFrFRMedium, + LocaleFrGP: DefaultFormatFrGPMedium, + LocaleFrCA: DefaultFormatFrCAMedium, + LocaleFrLU: DefaultFormatFrLUMedium, + LocaleFrMQ: DefaultFormatFrMQMedium, + LocaleFrGF: DefaultFormatFrGFMedium, + LocaleFrRE: DefaultFormatFrREMedium, + LocaleDeDE: DefaultFormatDeDEMedium, + LocaleHuHU: DefaultFormatHuHUMedium, + LocaleItIT: DefaultFormatItITMedium, + LocaleNnNO: DefaultFormatNnNOMedium, + LocaleNbNO: DefaultFormatNbNOMedium, + LocalePtPT: DefaultFormatPtPTMedium, + LocalePtBR: DefaultFormatPtBRMedium, + LocaleRoRO: DefaultFormatRoROMedium, + LocaleRuRU: DefaultFormatRuRUMedium, + LocaleEsES: DefaultFormatEsESMedium, + LocaleCaES: DefaultFormatCaESMedium, + LocaleSvSE: DefaultFormatSvSEMedium, + LocaleTrTR: DefaultFormatTrTRMedium, + LocaleBgBG: DefaultFormatBgBGMedium, + LocaleZhCN: DefaultFormatZhCNMedium, + LocaleZhTW: DefaultFormatZhTWMedium, + LocaleZhHK: DefaultFormatZhHKMedium, + LocaleKoKR: DefaultFormatKoKRMedium, + LocaleJaJP: DefaultFormatJaJPMedium, + LocaleElGR: DefaultFormatElGRMedium, + LocaleCsCZ: DefaultFormatCsCZMedium, +} + +// ShortFormatsByLocale maps locales to the 'short' date formats for all +// supported locales. +var ShortFormatsByLocale = map[Locale]string{ + LocaleEnUS: DefaultFormatEnUSShort, + LocaleEnGB: DefaultFormatEnGBShort, + LocaleDaDK: DefaultFormatDaDKShort, + LocaleNlBE: DefaultFormatNlBEShort, + LocaleNlNL: DefaultFormatNlNLShort, + LocaleFiFI: DefaultFormatFiFIShort, + LocaleFrFR: DefaultFormatFrFRShort, + LocaleFrCA: DefaultFormatFrCAShort, + LocaleFrLU: DefaultFormatFrLUShort, + LocaleFrMQ: DefaultFormatFrMQShort, + LocaleFrGF: DefaultFormatFrGFShort, + LocaleFrGP: DefaultFormatFrGPShort, + LocaleFrRE: DefaultFormatFrREShort, + LocaleDeDE: DefaultFormatDeDEShort, + LocaleHuHU: DefaultFormatHuHUShort, + LocaleItIT: DefaultFormatItITShort, + LocaleNnNO: DefaultFormatNnNOShort, + LocaleNbNO: DefaultFormatNbNOShort, + LocalePtPT: DefaultFormatPtPTShort, + LocalePtBR: DefaultFormatPtBRShort, + LocaleRoRO: DefaultFormatRoROShort, + LocaleRuRU: DefaultFormatRuRUShort, + LocaleEsES: DefaultFormatEsESShort, + LocaleCaES: DefaultFormatCaESShort, + LocaleSvSE: DefaultFormatSvSEShort, + LocaleTrTR: DefaultFormatTrTRShort, + LocaleBgBG: DefaultFormatBgBGShort, + LocaleZhCN: DefaultFormatZhCNShort, + LocaleZhTW: DefaultFormatZhTWShort, + LocaleZhHK: DefaultFormatZhHKShort, + LocaleKoKR: DefaultFormatKoKRShort, + LocaleJaJP: DefaultFormatJaJPShort, + LocaleElGR: DefaultFormatElGRShort, + LocaleCsCZ: DefaultFormatCsCZShort, +} + +// DateTimeFormatsByLocale maps locales to the 'DateTime' date formats for +// all supported locales. +var DateTimeFormatsByLocale = map[Locale]string{ + LocaleEnUS: DefaultFormatEnUSDateTime, + LocaleEnGB: DefaultFormatEnGBDateTime, + LocaleDaDK: DefaultFormatDaDKDateTime, + LocaleNlBE: DefaultFormatNlBEDateTime, + LocaleNlNL: DefaultFormatNlNLDateTime, + LocaleFiFI: DefaultFormatFiFIDateTime, + LocaleFrFR: DefaultFormatFrFRDateTime, + LocaleFrCA: DefaultFormatFrCADateTime, + LocaleFrGP: DefaultFormatFrGPDateTime, + LocaleFrLU: DefaultFormatFrLUDateTime, + LocaleFrMQ: DefaultFormatFrMQDateTime, + LocaleFrGF: DefaultFormatFrGFDateTime, + LocaleFrRE: DefaultFormatFrREDateTime, + LocaleDeDE: DefaultFormatDeDEDateTime, + LocaleHuHU: DefaultFormatHuHUDateTime, + LocaleItIT: DefaultFormatItITDateTime, + LocaleNnNO: DefaultFormatNnNODateTime, + LocaleNbNO: DefaultFormatNbNODateTime, + LocalePtPT: DefaultFormatPtPTDateTime, + LocalePtBR: DefaultFormatPtBRDateTime, + LocaleRoRO: DefaultFormatRoRODateTime, + LocaleRuRU: DefaultFormatRuRUDateTime, + LocaleEsES: DefaultFormatEsESDateTime, + LocaleCaES: DefaultFormatCaESDateTime, + LocaleSvSE: DefaultFormatSvSEDateTime, + LocaleTrTR: DefaultFormatTrTRDateTime, + LocaleBgBG: DefaultFormatBgBGDateTime, + LocaleZhCN: DefaultFormatZhCNDateTime, + LocaleZhTW: DefaultFormatZhTWDateTime, + LocaleZhHK: DefaultFormatZhHKDateTime, + LocaleKoKR: DefaultFormatKoKRDateTime, + LocaleJaJP: DefaultFormatJaJPDateTime, + LocaleElGR: DefaultFormatElGRDateTime, + LocaleCsCZ: DefaultFormatCsCZDateTime, +} diff --git a/vendor/github.com/goodsign/monday/default_orders.go b/vendor/github.com/goodsign/monday/default_orders.go new file mode 100644 index 0000000..9c524b3 --- /dev/null +++ b/vendor/github.com/goodsign/monday/default_orders.go @@ -0,0 +1,71 @@ +package monday + +var dayLongOrderMondayFirst = []string{ + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", + "Sunday", +} + +var dayLongOrderSundayFirst = []string{ + "Sunday", + "Monday", + "Tuesday", + "Wednesday", + "Thursday", + "Friday", + "Saturday", +} + +var dayShortOrderMondayFirst = []string{ + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", + "Sun", +} + +var dayShortOrderSundayFirst = []string{ + "Sun", + "Mon", + "Tue", + "Wed", + "Thu", + "Fri", + "Sat", +} + +var monthLongOrder = []string{ + "January", + "February", + "March", + "April", + "May", + "June", + "July", + "August", + "September", + "October", + "November", + "December", +} + +var monthShortOrder = []string{ + "Jan", + "Feb", + "Mar", + "Apr", + "May", + "Jun", + "Jul", + "Aug", + "Sep", + "Oct", + "Nov", + "Dec", +} diff --git a/vendor/github.com/goodsign/monday/doc.go b/vendor/github.com/goodsign/monday/doc.go new file mode 100644 index 0000000..fcd20cc --- /dev/null +++ b/vendor/github.com/goodsign/monday/doc.go @@ -0,0 +1,38 @@ +/* +Package monday is a minimalistic translator for month and day of week names in time.Date objects + +Introduction + +Monday is not an alternative to standard time package. It is a temporary solution to use while +the internationalization features are not ready. + +That's why monday doesn't create any additional parsing algorithms, layout identifiers. It is just +a wrapper for time.Format and time.ParseInLocation and uses all the same layout IDs, constants, etc. + +Usage + +Format usage: + + t := time.Date(2013, 4, 12, 0, 0, 0, 0, time.UTC) + layout := "2 January 2006 15:04:05 MST" + + translationEnUS := monday.Format(t, layout, monday.LocaleEnUS) // Instead of t.Format(layout) + translationRuRU := monday.Format(t, layout, monday.LocaleRuRU) // Instead of t.Format(layout) + ... + +Parse usage: + layout := "2 January 2006 15:04:05 MST" + + // Instead of time.ParseInLocation(layout, "12 April 2013 00:00:00 MST", time.UTC) + parsed := monday.ParseInLocation(layout, "12 April 2013 00:00:00 MST", time.UTC, monday.LocaleEnUS)) + parsed2 = monday.ParseInLocation(layout, "12 апреля 2013 00:00:00 MST", time.UTC, monday.LocaleRuRU)) + ... + +Thread safety + +Monday initializes all its data once in the init func and then uses only +func calls and local vars. Thus, it's thread-safe and doesn't need any mutexes to be +used with. + +*/ +package monday diff --git a/vendor/github.com/goodsign/monday/format_bg_bg.go b/vendor/github.com/goodsign/monday/format_bg_bg.go new file mode 100644 index 0000000..845312a --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_bg_bg.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "bg_BG" locale: Bulgarian (Bulgaria) +// ============================================================ + +var longDayNamesBgBG = map[string]string{ + "Sunday": "Неделя", + "Monday": "Понеделник", + "Tuesday": "Вторник", + "Wednesday": "Сряда", + "Thursday": "Четвъртък", + "Friday": "Петък", + "Saturday": "Събота", +} + +var shortDayNamesBgBG = map[string]string{ + "Sun": "Нд", + "Mon": "Пн", + "Tue": "Вт", + "Wed": "Ср", + "Thu": "Чt", + "Fri": "Пт", + "Sat": "Сб", +} + +var longMonthNamesBgBG = map[string]string{ + "January": "Януари", + "February": "Февруари", + "March": "Март", + "April": "Април", + "May": "Май", + "June": "Юни", + "July": "Юли", + "August": "Август", + "September": "Септември", + "October": "Октомври", + "November": "Ноември", + "December": "Декември", +} + +var shortMonthNamesBgBG = map[string]string{ + "Jan": "Яну", + "Feb": "Фев", + "Mar": "Мар", + "Apr": "Апр", + "May": "Май", + "Jun": "Юни", + "Jul": "Юли", + "Aug": "Авг", + "Sep": "Сеп", + "Oct": "Окт", + "Nov": "Ное", + "Dec": "Дек", +} diff --git a/vendor/github.com/goodsign/monday/format_ca_es.go b/vendor/github.com/goodsign/monday/format_ca_es.go new file mode 100644 index 0000000..9035c5f --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_ca_es.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "ca_ES" locale: Catalan (Spain) +// ============================================================ + +var longDayNamesCaES = map[string]string{ + "Sunday": "diumenge", + "Monday": "dilluns", + "Tuesday": "dimarts", + "Wednesday": "dimecres", + "Thursday": "dijous", + "Friday": "divendres", + "Saturday": "dissabte", +} + +var shortDayNamesCaES = map[string]string{ + "Sun": "dg", + "Mon": "dl", + "Tue": "dt", + "Wed": "dc", + "Thu": "dj", + "Fri": "dv", + "Sat": "ds", +} + +var longMonthNamesCaES = map[string]string{ + "January": "gener", + "February": "febrer", + "March": "març", + "April": "abril", + "May": "maig", + "June": "juny", + "July": "juliol", + "August": "agost", + "September": "setembre", + "October": "octubre", + "November": "novembre", + "December": "desembre", +} + +var shortMonthNamesCaES = map[string]string{ + "Jan": "gen", + "Feb": "febr", + "Mar": "març", + "Apr": "abr", + "May": "maig", + "Jun": "juny", + "Jul": "jul", + "Aug": "ag", + "Sep": "set", + "Oct": "oct", + "Nov": "nov", + "Dec": "des", +} diff --git a/vendor/github.com/goodsign/monday/format_common.go b/vendor/github.com/goodsign/monday/format_common.go new file mode 100644 index 0000000..5091b95 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_common.go @@ -0,0 +1,183 @@ +package monday + +import "strings" + +func findInString(where string, what string, foundIndex *int, trimRight *int) (found bool) { + ind := strings.Index(strings.ToLower(where), strings.ToLower(what)) + if ind != -1 { + *foundIndex = ind + *trimRight = len(where) - ind - len(what) + return true + } + + return false +} + +// commonFormatFunc is used for languages which don't have changed forms of month names dependent +// on their position (after day or standalone) +func commonFormatFunc(value, format string, + knownDaysShort, knownDaysLong, knownMonthsShort, knownMonthsLong, knownPeriods map[string]string) string { + l := stringToLayoutItems(value) + f := stringToLayoutItems(format) + if len(l) != len(f) { + return value // layouts does not matches + } + + sb := &strings.Builder{} + sb.Grow(32) // Reasonable default size that should fit most strings. + + for i, v := range l { + + var knw map[string]string + + // number of symbols before replaced term + foundIndex := 0 + trimRight := 0 + lowerCase := false + switch { + case findInString(f[i].item, "Monday", &foundIndex, &trimRight): + knw = knownDaysLong + case findInString(f[i].item, "Mon", &foundIndex, &trimRight): + knw = knownDaysShort + case findInString(f[i].item, "January", &foundIndex, &trimRight): + knw = knownMonthsLong + case findInString(f[i].item, "Jan", &foundIndex, &trimRight): + knw = knownMonthsShort + case findInString(f[i].item, "PM", &foundIndex, &trimRight): + knw = knownPeriods + case findInString(f[i].item, "pm", &foundIndex, &trimRight): + lowerCase = true + knw = knownPeriods + } + + knw = mapToLowerCase(knw) + + if knw != nil { + trimmedItem := strings.ToLower(v.item[foundIndex : len(v.item)-trimRight]) + + tr, ok := knw[trimmedItem] + if lowerCase == true { + tr = strings.ToLower(tr) + } + + if ok { + sb.WriteString(v.item[:foundIndex]) + sb.WriteString(tr) + sb.WriteString(v.item[len(v.item)-trimRight:]) + } else { + sb.WriteString(v.item) + } + } else { + sb.WriteString(v.item) + } + } + return sb.String() +} + +func hasDigitBefore(l []dateStringLayoutItem, position int) bool { + if position >= 2 { + return l[position-2].isDigit && len(l[position-2].item) <= 2 + } + return false +} + +// commonGenitiveFormatFunc is used for languages with genitive forms of names, like Russian. +func commonGenitiveFormatFunc(value, format string, + knownDaysShort, knownDaysLong, knownMonthsShort, knownMonthsLong, + knownMonthsGenShort, knownMonthsGenLong, knownPeriods map[string]string) string { + + l := stringToLayoutItems(value) + f := stringToLayoutItems(format) + + if len(l) != len(f) { + return value // layouts does not matches + } + + sb := &strings.Builder{} + sb.Grow(32) // Reasonable default size that should fit most strings. + + for i, v := range l { + lowerCase := false + var knw map[string]string + switch f[i].item { + case "Mon": + knw = knownDaysShort + case "Monday": + knw = knownDaysLong + case "Jan": + if hasDigitBefore(l, i) { + knw = knownMonthsGenShort + } else { + knw = knownMonthsShort + } + case "January": + if hasDigitBefore(l, i) { + knw = knownMonthsGenLong + } else { + knw = knownMonthsLong + } + case "PM": + knw = knownPeriods + case "pm": + lowerCase = true + knw = knownPeriods + } + + knw = mapToLowerCase(knw) + + if knw != nil { + tr, ok := knw[strings.ToLower(v.item)] + if !ok { + sb.WriteString(v.item) + continue + } + if lowerCase == true { + tr = strings.ToLower(tr) + } + sb.WriteString(tr) + } else { + sb.WriteString(v.item) + } + } + return sb.String() +} + +func createCommonFormatFunc(locale Locale) internalFormatFunc { + return func(value, layout string) (res string) { + return commonFormatFunc(value, layout, + knownDaysShort[locale], knownDaysLong[locale], knownMonthsShort[locale], knownMonthsLong[locale], knownPeriods[locale]) + } +} + +func createCommonFormatFuncWithGenitive(locale Locale) internalFormatFunc { + return func(value, layout string) (res string) { + return commonGenitiveFormatFunc(value, layout, + knownDaysShort[locale], knownDaysLong[locale], knownMonthsShort[locale], knownMonthsLong[locale], + knownMonthsGenitiveShort[locale], knownMonthsGenitiveLong[locale], knownPeriods[locale]) + } +} + +func createCommonParseFunc(locale Locale) internalParseFunc { + return func(layout, value string) string { + return commonFormatFunc(value, layout, + knownDaysShortReverse[locale], knownDaysLongReverse[locale], + knownMonthsShortReverse[locale], knownMonthsLongReverse[locale], knownPeriodsReverse[locale]) + } +} + +func createCommonParsetFuncWithGenitive(locale Locale) internalParseFunc { + return func(layout, value string) (res string) { + return commonGenitiveFormatFunc(value, layout, + knownDaysShortReverse[locale], knownDaysLongReverse[locale], + knownMonthsShortReverse[locale], knownMonthsLongReverse[locale], + knownMonthsGenitiveShortReverse[locale], knownMonthsGenitiveLongReverse[locale], knownPeriodsReverse[locale]) + } +} + +func mapToLowerCase(source map[string]string) map[string]string { + result := make(map[string]string, len(source)) + for k, v := range source { + result[strings.ToLower(k)] = v + } + return result +} diff --git a/vendor/github.com/goodsign/monday/format_cs_cz.go b/vendor/github.com/goodsign/monday/format_cs_cz.go new file mode 100644 index 0000000..906dcab --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_cs_cz.go @@ -0,0 +1,85 @@ +package monday + +// ============================================================ +// Format rules for "cs_CZ" locale: Czech (Czech Republic) +// ============================================================ + +var longDayNamesCsCZ = map[string]string{ + "Sunday": "neděle", + "Monday": "pondělí", + "Tuesday": "úterý", + "Wednesday": "středa", + "Thursday": "čtvrtek", + "Friday": "pátek", + "Saturday": "sobota", +} + +var shortDayNamesCsCZ = map[string]string{ + "Sun": "ne", + "Mon": "po", + "Tue": "út", + "Wed": "st", + "Thu": "čt", + "Fri": "pá", + "Sat": "so", +} + +var longMonthNamesCsCZ = map[string]string{ + "January": "leden", + "February": "únor", + "March": "březen", + "April": "duben", + "May": "květen", + "June": "červen", + "July": "červenec", + "August": "srpen", + "September": "září", + "October": "říjen", + "November": "listopad", + "December": "prosinec", +} + +var shortMonthNamesCsCZ = map[string]string{ + "Jan": "led", + "Feb": "úno", + "Mar": "bře", + "Apr": "dub", + "May": "kvě", + "Jun": "čvn", + "Jul": "čvc", + "Aug": "srp", + "Sep": "zář", + "Oct": "říj", + "Nov": "lis", + "Dec": "pro", +} + +var longMonthNamesGenitiveCsCZ = map[string]string{ + "January": "ledna", + "February": "února", + "March": "března", + "April": "dubna", + "May": "května", + "June": "června", + "July": "července", + "August": "srpna", + "September": "září", + "October": "října", + "November": "listopadu", + "December": "prosince", +} + +var shortMonthNamesGenitiveCsCZ = map[string]string{ + "Jan": "led", + "Feb": "úno", + "Mar": "bře", + "Apr": "dub", + "May": "kvě", + "Jun": "čvn", + "Jul": "čvc", + "Aug": "srp", + "Sep": "zář", + "Oct": "říj", + "Nov": "lis", + "Dec": "pro", +} diff --git a/vendor/github.com/goodsign/monday/format_da_dk.go b/vendor/github.com/goodsign/monday/format_da_dk.go new file mode 100644 index 0000000..5dee94e --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_da_dk.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "da_DK" locale: Danish (Denmark) +// ============================================================ + +var longDayNamesDaDK = map[string]string{ + "Sunday": "søndag", + "Monday": "mandag", + "Tuesday": "tirsdag", + "Wednesday": "onsdag", + "Thursday": "torsdag", + "Friday": "fredag", + "Saturday": "lørdag", +} + +var shortDayNamesDaDK = map[string]string{ + "Sun": "søn", + "Mon": "man", + "Tue": "tir", + "Wed": "ons", + "Thu": "tor", + "Fri": "fre", + "Sat": "lør", +} + +var longMonthNamesDaDK = map[string]string{ + "January": "januar", + "February": "februar", + "March": "marts", + "April": "april", + "May": "maj", + "June": "juni", + "July": "juli", + "August": "august", + "September": "september", + "October": "oktober", + "November": "november", + "December": "december", +} + +var shortMonthNamesDaDK = map[string]string{ + "Jan": "jan", + "Feb": "feb", + "Mar": "mar", + "Apr": "apr", + "May": "maj", + "Jun": "jun", + "Jul": "jul", + "Aug": "aug", + "Sep": "sep", + "Oct": "okt", + "Nov": "nov", + "Dec": "dec", +} diff --git a/vendor/github.com/goodsign/monday/format_de_de.go b/vendor/github.com/goodsign/monday/format_de_de.go new file mode 100644 index 0000000..28867ee --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_de_de.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "de_DE" locale: German (Germany) +// ============================================================ + +var longDayNamesDeDE = map[string]string{ + "Sunday": "Sonntag", + "Monday": "Montag", + "Tuesday": "Dienstag", + "Wednesday": "Mittwoch", + "Thursday": "Donnerstag", + "Friday": "Freitag", + "Saturday": "Samstag", +} + +var shortDayNamesDeDE = map[string]string{ + "Sun": "So", + "Mon": "Mo", + "Tue": "Di", + "Wed": "Mi", + "Thu": "Do", + "Fri": "Fr", + "Sat": "Sa", +} + +var longMonthNamesDeDE = map[string]string{ + "January": "Januar", + "February": "Februar", + "March": "März", + "April": "April", + "May": "Mai", + "June": "Juni", + "July": "Juli", + "August": "August", + "September": "September", + "October": "Oktober", + "November": "November", + "December": "Dezember", +} + +var shortMonthNamesDeDE = map[string]string{ + "Jan": "Jan", + "Feb": "Feb", + "Mar": "Mär", + "Apr": "Apr", + "May": "Mai", + "Jun": "Juni", + "Jul": "Juli", + "Aug": "Aug", + "Sep": "Sep", + "Oct": "Okt", + "Nov": "Nov", + "Dec": "Dez", +} diff --git a/vendor/github.com/goodsign/monday/format_el_gr.go b/vendor/github.com/goodsign/monday/format_el_gr.go new file mode 100644 index 0000000..37bc44f --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_el_gr.go @@ -0,0 +1,77 @@ +package monday + +// ============================================================ +// Format rules for "el_GR" locale: Greek (Greece) +// ============================================================ + +var longDayNamesElGR = map[string]string{ + "Sunday": "Κυριακή", + "Monday": "Δευτέρα", + "Tuesday": "Τρίτη", + "Wednesday": "Τετάρτη", + "Thursday": "Πέμπτη", + "Friday": "Παρασκευή", + "Saturday": "Σάββατο", +} + +var shortDayNamesElGR = map[string]string{ + "Sun": "Κυρ", + "Mon": "Δευ", + "Tue": "Τρι", + "Wed": "Τετ", + "Thu": "Πεμ", + "Fri": "Παρ", + "Sat": "Σαβ", +} + +var longMonthNamesElGR = map[string]string{ + "January": "Ιανουάριος", + "February": "Φεβρουάριος", + "March": "Μάρτιος", + "April": "Απρίλιος", + "May": "Μάιος", + "June": "Ιούνιος", + "July": "Ιούλιος", + "August": "Αύγουστος", + "September": "Σεπτέμβριος", + "October": "Οκτώβριος", + "November": "Νοέμβριος", + "December": "Δεκέμβριος", +} + +var longMonthNamesGenitiveElGR = map[string]string{ + "January": "Ιανουαρίου", + "February": "Φεβρουαρίου", + "March": "Μαρτίου", + "April": "Απριλίου", + "May": "Μαΐου", + "June": "Ιουνίου", + "July": "Ιουλίου", + "August": "Αυγούστου", + "September": "Σεπτεμβρίου", + "October": "Οκτωβρίου", + "November": "Νοεμβρίου", + "December": "Δεκεμβρίου", +} + +var shortMonthNamesElGR = map[string]string{ + "Jan": "Ιαν", + "Feb": "Φεβ", + "Mar": "Μαρ", + "Apr": "Απρ", + "May": "Μαϊ", + "Jun": "Ιουν", + "Jul": "Ιουλ", + "Aug": "Αυγ", + "Sep": "Σεπ", + "Oct": "Οκτ", + "Nov": "Νοε", + "Dec": "Δεκ", +} + +var periodsElGR = map[string]string{ + "am": "πμ", + "pm": "μμ", + "AM": "ΠΜ", + "PM": "ΜΜ", +} diff --git a/vendor/github.com/goodsign/monday/format_en_gb.go b/vendor/github.com/goodsign/monday/format_en_gb.go new file mode 100644 index 0000000..5f668c4 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_en_gb.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "en_GB" locale: English (Great Britain) +// ============================================================ + +var longDayNamesEnGB = map[string]string{ + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", +} + +var shortDayNamesEnGB = map[string]string{ + "Sun": "Sun", + "Mon": "Mon", + "Tue": "Tue", + "Wed": "Wed", + "Thu": "Thu", + "Fri": "Fri", + "Sat": "Sat", +} + +var longMonthNamesEnGB = map[string]string{ + "January": "January", + "February": "February", + "March": "March", + "April": "April", + "May": "May", + "June": "June", + "July": "July", + "August": "August", + "September": "September", + "October": "October", + "November": "November", + "December": "December", +} + +var shortMonthNamesEnGB = map[string]string{ + "Jan": "Jan", + "Feb": "Feb", + "Mar": "Mar", + "Apr": "Apr", + "May": "May", + "Jun": "Jun", + "Jul": "Jul", + "Aug": "Aug", + "Sep": "Sep", + "Oct": "Oct", + "Nov": "Nov", + "Dec": "Dec", +} diff --git a/vendor/github.com/goodsign/monday/format_en_us.go b/vendor/github.com/goodsign/monday/format_en_us.go new file mode 100644 index 0000000..9289308 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_en_us.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "en_US" locale: English (United States) +// ============================================================ + +var longDayNamesEnUS = map[string]string{ + "Sunday": "Sunday", + "Monday": "Monday", + "Tuesday": "Tuesday", + "Wednesday": "Wednesday", + "Thursday": "Thursday", + "Friday": "Friday", + "Saturday": "Saturday", +} + +var shortDayNamesEnUS = map[string]string{ + "Sun": "Sun", + "Mon": "Mon", + "Tue": "Tue", + "Wed": "Wed", + "Thu": "Thu", + "Fri": "Fri", + "Sat": "Sat", +} + +var longMonthNamesEnUS = map[string]string{ + "January": "January", + "February": "February", + "March": "March", + "April": "April", + "May": "May", + "June": "June", + "July": "July", + "August": "August", + "September": "September", + "October": "October", + "November": "November", + "December": "December", +} + +var shortMonthNamesEnUS = map[string]string{ + "Jan": "Jan", + "Feb": "Feb", + "Mar": "Mar", + "Apr": "Apr", + "May": "May", + "Jun": "Jun", + "Jul": "Jul", + "Aug": "Aug", + "Sep": "Sep", + "Oct": "Oct", + "Nov": "Nov", + "Dec": "Dec", +} diff --git a/vendor/github.com/goodsign/monday/format_es_es.go b/vendor/github.com/goodsign/monday/format_es_es.go new file mode 100644 index 0000000..9baf26a --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_es_es.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "es_ES" locale: Spanish (Spain) +// ============================================================ + +var longDayNamesEsES = map[string]string{ + "Sunday": "domingo", + "Monday": "lunes", + "Tuesday": "martes", + "Wednesday": "miércoles", + "Thursday": "jueves", + "Friday": "viernes", + "Saturday": "sábado", +} + +var shortDayNamesEsES = map[string]string{ + "Sun": "dom", + "Mon": "lun", + "Tue": "mar", + "Wed": "mié", + "Thu": "jue", + "Fri": "vie", + "Sat": "sáb", +} + +var longMonthNamesEsES = map[string]string{ + "January": "enero", + "February": "febrero", + "March": "marzo", + "April": "abril", + "May": "mayo", + "June": "junio", + "July": "julio", + "August": "agosto", + "September": "septiembre", + "October": "octubre", + "November": "noviembre", + "December": "diciembre", +} + +var shortMonthNamesEsES = map[string]string{ + "Jan": "ene", + "Feb": "feb", + "Mar": "mar", + "Apr": "abr", + "May": "may", + "Jun": "jun", + "Jul": "jul", + "Aug": "ago", + "Sep": "sep", + "Oct": "oct", + "Nov": "nov", + "Dec": "dic", +} diff --git a/vendor/github.com/goodsign/monday/format_fi_fi.go b/vendor/github.com/goodsign/monday/format_fi_fi.go new file mode 100644 index 0000000..b290b7b --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_fi_fi.go @@ -0,0 +1,70 @@ +package monday + +// ============================================================ +// Format rules for "fi_FI" locale: Finnish (Finland) +// ============================================================ + +var longDayNamesFiFI = map[string]string{ + "Sunday": "sunnuntai", + "Monday": "maanantai", + "Tuesday": "tiistai", + "Wednesday": "keskiviikko", + "Thursday": "torstai", + "Friday": "perjantai", + "Saturday": "lauantai", +} + +var shortDayNamesFiFI = map[string]string{ + "Sun": "su", + "Mon": "ma", + "Tue": "ti", + "Wed": "ke", + "Thu": "to", + "Fri": "pe", + "Sat": "la", +} + +var longMonthNamesFiFI = map[string]string{ + "January": "tammikuu", + "February": "helmikuu", + "March": "maaliskuu", + "April": "huhtikuu", + "May": "toukokuu", + "June": "kesäkuu", + "July": "heinäkuu", + "August": "elokuu", + "September": "syyskuu", + "October": "lokakuu", + "November": "marraskuu", + "December": "joulukuu", +} + +var longMonthNamesGenitiveFiFI = map[string]string{ + "January": "tammikuuta", + "February": "helmikuuta", + "March": "maaliskuuta", + "April": "huhtikuuta", + "May": "toukokuuta", + "June": "kesäkuuta", + "July": "heinäkuuta", + "August": "elokuuta", + "September": "syyskuuta", + "October": "lokakuuta", + "November": "marraskuuta", + "December": "joulukuuta", +} + +var shortMonthNamesFiFI = map[string]string{ + "Jan": "tammi", + "Feb": "helmi", + "Mar": "maalis", + "Apr": "huhti", + "May": "touko", + "Jun": "kesä", + "Jul": "heinä", + "Aug": "elo", + "Sep": "syys", + "Oct": "loka", + "Nov": "marras", + "Dec": "joulu", +} diff --git a/vendor/github.com/goodsign/monday/format_fr_fr.go b/vendor/github.com/goodsign/monday/format_fr_fr.go new file mode 100644 index 0000000..a25d859 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_fr_fr.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "fr_FR" locale: French (France) +// ============================================================ + +var longDayNamesFrFR = map[string]string{ + "Sunday": "dimanche", + "Monday": "lundi", + "Tuesday": "mardi", + "Wednesday": "mercredi", + "Thursday": "jeudi", + "Friday": "vendredi", + "Saturday": "samedi", +} + +var shortDayNamesFrFR = map[string]string{ + "Sun": "dim", + "Mon": "lun", + "Tue": "mar", + "Wed": "mer", + "Thu": "jeu", + "Fri": "ven", + "Sat": "sam", +} + +var longMonthNamesFrFR = map[string]string{ + "January": "janvier", + "February": "février", + "March": "mars", + "April": "avril", + "May": "mai", + "June": "juin", + "July": "juillet", + "August": "août", + "September": "septembre", + "October": "octobre", + "November": "novembre", + "December": "décembre", +} + +var shortMonthNamesFrFR = map[string]string{ + "Jan": "janv", + "Feb": "févr", + "Mar": "mars", + "Apr": "avr", + "May": "mai", + "Jun": "juin", + "Jul": "juil", + "Aug": "août", + "Sep": "sept", + "Oct": "oct", + "Nov": "nov", + "Dec": "déc", +} diff --git a/vendor/github.com/goodsign/monday/format_hu_hu.go b/vendor/github.com/goodsign/monday/format_hu_hu.go new file mode 100644 index 0000000..4d10c9d --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_hu_hu.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "hu_HU" locale: Hungarian (Hungary) +// ============================================================ + +var longDayNamesHuHU = map[string]string{ + "Sunday": "vasárnap", + "Monday": "hétfő", + "Tuesday": "kedd", + "Wednesday": "szerda", + "Thursday": "csütörtök", + "Friday": "péntek", + "Saturday": "szombat", +} + +var shortDayNamesHuHU = map[string]string{ + "Sun": "V", + "Mon": "H", + "Tue": "K", + "Wed": "Sze", + "Thu": "Cs", + "Fri": "P", + "Sat": "Szo", +} + +var longMonthNamesHuHU = map[string]string{ + "January": "január", + "February": "február", + "March": "március", + "April": "április", + "May": "május", + "June": "június", + "July": "július", + "August": "augusztus", + "September": "szeptember", + "October": "október", + "November": "november", + "December": "december", +} + +var shortMonthNamesHuHU = map[string]string{ + "Jan": "jan", + "Feb": "febr", + "Mar": "márc", + "Apr": "ápr", + "May": "máj", + "Jun": "jún", + "Jul": "júl", + "Aug": "aug", + "Sep": "szept", + "Oct": "okt", + "Nov": "nov", + "Dec": "dec", +} diff --git a/vendor/github.com/goodsign/monday/format_id_id.go b/vendor/github.com/goodsign/monday/format_id_id.go new file mode 100644 index 0000000..b4184c9 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_id_id.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "id_ID" locale: Indonesian (Indonesia) +// ============================================================ + +var longDayNamesIdID = map[string]string{ + "Sunday": "Minggu", + "Monday": "Senin", + "Tuesday": "Selasa", + "Wednesday": "Rabu", + "Thursday": "Kamis", + "Friday": "Jumat", + "Saturday": "Sabtu", +} + +var shortDayNamesIdID = map[string]string{ + "Sun": "Min", + "Mon": "Sen", + "Tue": "Sel", + "Wed": "Rab", + "Thu": "Kam", + "Fri": "Jum", + "Sat": "Sab", +} + +var longMonthNamesIdID = map[string]string{ + "January": "Januari", + "February": "Februari", + "March": "Maret", + "April": "April", + "May": "Mei", + "June": "Juni", + "July": "Juli", + "August": "Agustus", + "September": "September", + "October": "Oktober", + "November": "November", + "December": "Desember", +} + +var shortMonthNamesIdID = map[string]string{ + "Jan": "Jan", + "Feb": "Feb", + "Mar": "Mar", + "Apr": "Apr", + "May": "Mei", + "Jun": "Jun", + "Jul": "Jul", + "Aug": "Ags", + "Sep": "Sep", + "Oct": "Okt", + "Nov": "Nov", + "Dec": "Des", +} diff --git a/vendor/github.com/goodsign/monday/format_it_it.go b/vendor/github.com/goodsign/monday/format_it_it.go new file mode 100644 index 0000000..dff12f3 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_it_it.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "it_IT" locale: Italian (Italy) +// ============================================================ + +var longDayNamesItIT = map[string]string{ + "Sunday": "domenica", + "Monday": "lunedì", + "Tuesday": "martedì", + "Wednesday": "mercoledì", + "Thursday": "giovedì", + "Friday": "venerdì", + "Saturday": "sabato", +} + +var shortDayNamesItIT = map[string]string{ + "Sun": "dom", + "Mon": "lun", + "Tue": "mar", + "Wed": "mer", + "Thu": "gio", + "Fri": "ven", + "Sat": "sab", +} + +var longMonthNamesItIT = map[string]string{ + "January": "gennaio", + "February": "febbraio", + "March": "marzo", + "April": "aprile", + "May": "maggio", + "June": "giugno", + "July": "luglio", + "August": "agosto", + "September": "settembre", + "October": "ottobre", + "November": "novembre", + "December": "dicembre", +} + +var shortMonthNamesItIT = map[string]string{ + "Jan": "gen", + "Feb": "feb", + "Mar": "mar", + "Apr": "apr", + "May": "mag", + "Jun": "giu", + "Jul": "lug", + "Aug": "ago", + "Sep": "set", + "Oct": "ott", + "Nov": "nov", + "Dec": "dic", +} diff --git a/vendor/github.com/goodsign/monday/format_ja_jp.go b/vendor/github.com/goodsign/monday/format_ja_jp.go new file mode 100644 index 0000000..51d7eb5 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_ja_jp.go @@ -0,0 +1,95 @@ +package monday + +import ( + "strings" +) + +// ============================================================ +// Format rules for "ja_JP" locale: Japanese +// ============================================================ + +var longDayNamesJaJP = map[string]string{ + "Sunday": "日曜日", + "Monday": "月曜日", + "Tuesday": "火曜日", + "Wednesday": "水曜日", + "Thursday": "木曜日", + "Friday": "金曜日", + "Saturday": "土曜日", +} + +var shortDayNamesJaJP = map[string]string{ + "Sun": "日", + "Mon": "月", + "Tue": "火", + "Wed": "水", + "Thu": "木", + "Fri": "金", + "Sat": "土", +} + +var longMonthNamesJaJP = map[string]string{ + "January": "1月", + "February": "2月", + "March": "3月", + "April": "4月", + "May": "5月", + "June": "6月", + "July": "7月", + "August": "8月", + "September": "9月", + "October": "10月", + "November": "11月", + "December": "12月", +} + +var shortMonthNamesJaJP = map[string]string{ + "Jan": "1月", + "Feb": "2月", + "Mar": "3月", + "Apr": "4月", + "May": "5月", + "Jun": "6月", + "Jul": "7月", + "Aug": "8月", + "Sep": "9月", + "Oct": "10月", + "Nov": "11月", + "Dec": "12月", +} + +var periodsJaJP = map[string]string{ + "am": "午前", + "pm": "午後", + "AM": "午前", + "PM": "午後", +} + +func parseFuncJaCommon(locale Locale) internalParseFunc { + return func(layout, value string) string { + // This special case is needed because ja_JP... contains month names + // that consist of a number, a delimiter, and '月'. Example: "October" = "10 月" + // + // This means that probably default time package layout IDs like 'January' or 'Jan' + // shouldn't be used in ja_JP. But this is a time-compatible package, so someone + // might actually use those and we need to replace those before doing standard procedures. + for k, v := range knownMonthsLongReverse[locale] { + value = strings.Replace(value, k, v, -1) + } + + value = commonFormatFunc(value, layout, + knownDaysShortReverse[locale], knownDaysLongReverse[locale], + knownMonthsShortReverse[locale], knownMonthsLongReverse[locale], knownPeriods[locale]) + + // knownPeriodsReverse has hash collisions + for k, v := range knownPeriodsReverse[locale] { + targetValue := strings.ToLower(v) + if strings.Index(layout, "PM") != -1 { + targetValue = strings.ToUpper(v) + } + value = strings.Replace(value, k, targetValue, -1) + } + + return value + } +} diff --git a/vendor/github.com/goodsign/monday/format_ko_kr.go b/vendor/github.com/goodsign/monday/format_ko_kr.go new file mode 100644 index 0000000..bab2093 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_ko_kr.go @@ -0,0 +1,94 @@ +package monday + +import "strings" + +// ============================================================ +// Format rules for "ko_KR" locale: Korean (Korea) +// ============================================================ + +var longDayNamesKoKR = map[string]string{ + "Sunday": "일요일", + "Monday": "월요일", + "Tuesday": "화요일", + "Wednesday": "수요일", + "Thursday": "목요일", + "Friday": "금요일", + "Saturday": "토요일", +} + +var shortDayNamesKoKR = map[string]string{ + "Sun": "일", + "Mon": "월", + "Tue": "화", + "Wed": "수", + "Thu": "목", + "Fri": "금", + "Sat": "토", +} + +var longMonthNamesKoKR = map[string]string{ + "January": "1월", + "February": "2월", + "March": "3월", + "April": "4월", + "May": "5월", + "June": "6월", + "July": "7월", + "August": "8월", + "September": "9월", + "October": "10월", + "November": "11월", + "December": "12월", +} + +var shortMonthNamesKoKR = map[string]string{ + "Jan": "1월", + "Feb": "2월", + "Mar": "3월", + "Apr": "4월", + "May": "5월", + "Jun": "6월", + "Jul": "7월", + "Aug": "8월", + "Sep": "9월", + "Oct": "10월", + "Nov": "11월", + "Dec": "12월", +} + +var periodsKoKR = map[string]string{ + "am": "오전", + "pm": "오후", + "AM": "오전", + "PM": "오후", +} + +func parseFuncKoCommon(locale Locale) internalParseFunc { + return func(layout, value string) string { + // This special case is needed because ko_KR... contains month names + // that consist of a number, a delimiter, and '월'. Example: "September" = "9 월" + // + // This means that probably default time package layout IDs like 'January' or 'Jan' + // shouldn't be used in ko_KR. But this is a time-compatible package, so someone + // might actually use those and we need to replace those before doing standard procedures. + + for k, v := range knownMonthsLongReverse[locale] { + value = strings.Replace(value, k, v, -1) + } + + value = commonFormatFunc(value, layout, + knownDaysShortReverse[locale], knownDaysLongReverse[locale], + knownMonthsShortReverse[locale], knownMonthsLongReverse[locale], knownPeriods[locale]) + + // knownPeriodsReverse has hash collisions + for k, v := range knownPeriodsReverse[locale] { + targetValue := strings.ToLower(v) + if strings.Index(layout, "PM") != -1 { + targetValue = strings.ToUpper(v) + } + value = strings.Replace(value, k, targetValue, -1) + } + + return value + } +} diff --git a/vendor/github.com/goodsign/monday/format_nb_no.go b/vendor/github.com/goodsign/monday/format_nb_no.go new file mode 100644 index 0000000..36d04ea --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_nb_no.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "nb_NO" locale: Norwegian Bokmål (Norway) +// ============================================================ + +var longDayNamesNbNO = map[string]string{ + "Sunday": "søndag", + "Monday": "mandag", + "Tuesday": "tirsdag", + "Wednesday": "onsdag", + "Thursday": "torsdag", + "Friday": "fredag", + "Saturday": "lørdag", +} + +var shortDayNamesNbNO = map[string]string{ + "Sun": "sø", + "Mon": "ma", + "Tue": "ti", + "Wed": "on", + "Thu": "to", + "Fri": "fr", + "Sat": "lø", +} + +var longMonthNamesNbNO = map[string]string{ + "January": "januar", + "February": "februar", + "March": "mars", + "April": "april", + "May": "mai", + "June": "juni", + "July": "juli", + "August": "august", + "September": "september", + "October": "oktober", + "November": "november", + "December": "desember", +} + +var shortMonthNamesNbNO = map[string]string{ + "Jan": "jan", + "Feb": "feb", + "Mar": "mar", + "Apr": "apr", + "May": "mai", + "Jun": "jun", + "Jul": "jul", + "Aug": "aug", + "Sep": "sep", + "Oct": "okt", + "Nov": "nov", + "Dec": "des", +} diff --git a/vendor/github.com/goodsign/monday/format_nl_be.go b/vendor/github.com/goodsign/monday/format_nl_be.go new file mode 100644 index 0000000..dfa7e54 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_nl_be.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "nl_BE" locale: Dutch (Belgium) +// ============================================================ + +var longDayNamesNlBE = map[string]string{ + "Sunday": "zondag", + "Monday": "maandag", + "Tuesday": "dinsdag", + "Wednesday": "woensdag", + "Thursday": "donderdag", + "Friday": "vrijdag", + "Saturday": "zaterdag", +} + +var shortDayNamesNlBE = map[string]string{ + "Sun": "zo", + "Mon": "ma", + "Tue": "di", + "Wed": "wo", + "Thu": "do", + "Fri": "vr", + "Sat": "za", +} + +var longMonthNamesNlBE = map[string]string{ + "January": "januari", + "February": "februari", + "March": "maart", + "April": "april", + "May": "mei", + "June": "juni", + "July": "juli", + "August": "augustus", + "September": "september", + "October": "oktober", + "November": "november", + "December": "december", +} + +var shortMonthNamesNlBE = map[string]string{ + "Jan": "jan", + "Feb": "feb", + "Mar": "mrt", + "Apr": "apr", + "May": "mei", + "Jun": "jun", + "Jul": "jul", + "Aug": "aug", + "Sep": "sep", + "Oct": "okt", + "Nov": "nov", + "Dec": "dec", +} diff --git a/vendor/github.com/goodsign/monday/format_nn_no.go b/vendor/github.com/goodsign/monday/format_nn_no.go new file mode 100644 index 0000000..d58af18 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_nn_no.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "nn_NO" locale: Norwegian Nynorsk (Norway) +// ============================================================ + +var longDayNamesNnNO = map[string]string{ + "Sunday": "søndag", + "Monday": "måndag", + "Tuesday": "tysdag", + "Wednesday": "onsdag", + "Thursday": "torsdag", + "Friday": "fredag", + "Saturday": "laurdag", +} + +var shortDayNamesNnNO = map[string]string{ + "Sun": "sø", + "Mon": "må", + "Tue": "ty", + "Wed": "on", + "Thu": "to", + "Fri": "fr", + "Sat": "la", +} + +var longMonthNamesNnNO = map[string]string{ + "January": "januar", + "February": "februar", + "March": "mars", + "April": "april", + "May": "mai", + "June": "juni", + "July": "juli", + "August": "august", + "September": "september", + "October": "oktober", + "November": "november", + "December": "desember", +} + +var shortMonthNamesNnNO = map[string]string{ + "Jan": "jan", + "Feb": "feb", + "Mar": "mars", + "Apr": "apr", + "May": "mai", + "Jun": "juni", + "Jul": "juli", + "Aug": "aug", + "Sep": "sep", + "Oct": "okt", + "Nov": "nov", + "Dec": "des", +} diff --git a/vendor/github.com/goodsign/monday/format_pl_pl.go b/vendor/github.com/goodsign/monday/format_pl_pl.go new file mode 100644 index 0000000..034f1bc --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_pl_pl.go @@ -0,0 +1,56 @@ +package monday + +// ============================================================ +// Format rules for "pl_PL" locale: Polish (Poland) +// ============================================================ + +var longDayNamesPlPL = map[string]string{ + "Sunday": "Niedziela", + "Monday": "Poniedziałek", + "Tuesday": "Wtorek", + "Wednesday": "Środa", + "Thursday": "Czwartek", + "Friday": "Piątek", + "Saturday": "Sobota", +} + +// http://sjp.pwn.pl/poradnia/haslo/skracanie-nazw-dni-tygodnia-i-miesiecy;8124.html +var shortDayNamesPlPL = map[string]string{ + "Sun": "Nie", + "Mon": "Pon", + "Tue": "Wto", + "Wed": "Śro", + "Thu": "Czw", + "Fri": "Pią", + "Sat": "Sob", +} + +var longMonthNamesPlPL = map[string]string{ + "January": "Styczeń", + "February": "Luty", + "March": "Marzec", + "April": "Kwiecień", + "May": "Maj", + "June": "Czerwiec", + "July": "Lipiec", + "August": "Sierpień", + "September": "Wrzesień", + "October": "Październik", + "November": "Listopad", + "December": "Grudzień", +} + +var shortMonthNamesPlPL = map[string]string{ + "Jan": "Sty", + "Feb": "Lut", + "Mar": "Mar", + "Apr": "Kwi", + "May": "Maj", + "Jun": "Cze", + "Jul": "Lip", + "Aug": "Sie", + "Sep": "Wrz", + "Oct": "Paź", + "Nov": "Lis", + "Dec": "Gru", +} diff --git a/vendor/github.com/goodsign/monday/format_pt_br.go b/vendor/github.com/goodsign/monday/format_pt_br.go new file mode 100644 index 0000000..ab6269e --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_pt_br.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "pt_BR" locale: Portuguese (Brazil) +// ============================================================ + +var longDayNamesPtBR = map[string]string{ + "Sunday": "domingo", + "Monday": "segunda-feira", + "Tuesday": "terça-feira", + "Wednesday": "quarta-feira", + "Thursday": "quinta-feira", + "Friday": "sexta-feira", + "Saturday": "sábado", +} + +var shortDayNamesPtBR = map[string]string{ + "Sun": "dom", + "Mon": "seg", + "Tue": "ter", + "Wed": "qua", + "Thu": "qui", + "Fri": "sex", + "Sat": "sáb", +} + +var longMonthNamesPtBR = map[string]string{ + "January": "janeiro", + "February": "fevereiro", + "March": "março", + "April": "abril", + "May": "maio", + "June": "junho", + "July": "julho", + "August": "agosto", + "September": "setembro", + "October": "outubro", + "November": "novembro", + "December": "dezembro", +} + +var shortMonthNamesPtBR = map[string]string{ + "Jan": "jan", + "Feb": "fev", + "Mar": "mar", + "Apr": "abr", + "May": "mai", + "Jun": "jun", + "Jul": "jul", + "Aug": "ago", + "Sep": "set", + "Oct": "out", + "Nov": "nov", + "Dec": "dez", +} diff --git a/vendor/github.com/goodsign/monday/format_pt_pt.go b/vendor/github.com/goodsign/monday/format_pt_pt.go new file mode 100644 index 0000000..5d3d750 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_pt_pt.go @@ -0,0 +1,72 @@ +package monday + +import "strings" + +// ============================================================ +// Format rules for "pt_PT" locale: Portuguese (Portugal) +// ============================================================ + +var longDayNamesPtPT = map[string]string{ + "Sunday": "Domingo", + "Monday": "Segunda-feira", + "Tuesday": "Terça-feira", + "Wednesday": "Quarta-feira", + "Thursday": "Quinta-feira", + "Friday": "Sexta-feira", + "Saturday": "Sábado", +} + +var shortDayNamesPtPT = map[string]string{ + "Sun": "dom", + "Mon": "seg", + "Tue": "ter", + "Wed": "qua", + "Thu": "qui", + "Fri": "sex", + "Sat": "sáb", +} + +var longMonthNamesPtPT = map[string]string{ + "January": "Janeiro", + "February": "Fevereiro", + "March": "Março", + "April": "Abril", + "May": "Maio", + "June": "Junho", + "July": "Julho", + "August": "Agosto", + "September": "Setembro", + "October": "Outubro", + "November": "Novembro", + "December": "Dezembro", +} + +var shortMonthNamesPtPT = map[string]string{ + "Jan": "Jan", + "Feb": "Fev", + "Mar": "Mar", + "Apr": "Abr", + "May": "Mai", + "Jun": "Jun", + "Jul": "Jul", + "Aug": "Ago", + "Sep": "Set", + "Oct": "Out", + "Nov": "Nov", + "Dec": "Dez", +} + +func parseFuncPtCommon(locale Locale) internalParseFunc { + return func(layout, value string) string { + // This special case is needed because Pt_PT/Pt_BR/... contains day-of-week names + // that consist of two words and a delimiter (like 'terça-feira'). These + // should be replaced before using the standard procedure correctly. + for k, v := range knownDaysLongReverse[locale] { + value = strings.Replace(value, k, v, -1) + } + + return commonFormatFunc(value, layout, + knownDaysShortReverse[locale], knownDaysLongReverse[locale], + knownMonthsShortReverse[locale], knownMonthsLongReverse[locale], knownPeriods[locale]) + } +} diff --git a/vendor/github.com/goodsign/monday/format_ro_RO.go b/vendor/github.com/goodsign/monday/format_ro_RO.go new file mode 100644 index 0000000..b4850de --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_ro_RO.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "ro_RO" locale: Romanian (Romania) +// ============================================================ + +var longDayNamesRoRO = map[string]string{ + "Sunday": "duminică", + "Monday": "luni", + "Tuesday": "marți", + "Wednesday": "miercuri", + "Thursday": "joi", + "Friday": "vineri", + "Saturday": "sâmbătă", +} + +var shortDayNamesRoRO = map[string]string{ + "Sun": "Du", + "Mon": "Lu", + "Tue": "Ma", + "Wed": "Mi", + "Thu": "Jo", + "Fri": "Vi", + "Sat": "Sâ", +} + +var longMonthNamesRoRO = map[string]string{ + "January": "ianuarie", + "February": "februarie", + "March": "martie", + "April": "aprilie", + "May": "mai", + "June": "iunie", + "July": "iulie", + "August": "august", + "September": "septembrie", + "October": "octombrie", + "November": "noiembrie", + "December": "decembrie", +} + +var shortMonthNamesRoRO = map[string]string{ + "Jan": "ian", + "Feb": "feb", + "Mar": "mar", + "Apr": "apr", + "May": "mai", + "Jun": "iun", + "Jul": "iul", + "Aug": "aug", + "Sep": "sept", + "Oct": "oct", + "Nov": "nov", + "Dec": "dec", +} diff --git a/vendor/github.com/goodsign/monday/format_ru_ru.go b/vendor/github.com/goodsign/monday/format_ru_ru.go new file mode 100644 index 0000000..e882e3e --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_ru_ru.go @@ -0,0 +1,85 @@ +package monday + +// ============================================================ +// Format rules for "ru_RU" locale: Russian (Russia) +// ============================================================ + +var longDayNamesRuRU = map[string]string{ + "Sunday": "Воскресенье", + "Monday": "Понедельник", + "Tuesday": "Вторник", + "Wednesday": "Среда", + "Thursday": "Четверг", + "Friday": "Пятница", + "Saturday": "Суббота", +} + +var shortDayNamesRuRU = map[string]string{ + "Sun": "Вс", + "Mon": "Пн", + "Tue": "Вт", + "Wed": "Ср", + "Thu": "Чт", + "Fri": "Пт", + "Sat": "Сб", +} + +var longMonthNamesRuRU = map[string]string{ + "January": "Январь", + "February": "Февраль", + "March": "Март", + "April": "Апрель", + "May": "Май", + "June": "Июнь", + "July": "Июль", + "August": "Август", + "September": "Сентябрь", + "October": "Октябрь", + "November": "Ноябрь", + "December": "Декабрь", +} + +var longMonthNamesGenitiveRuRU = map[string]string{ + "January": "января", + "February": "февраля", + "March": "марта", + "April": "апреля", + "May": "мая", + "June": "июня", + "July": "июля", + "August": "августа", + "September": "сентября", + "October": "октября", + "November": "ноября", + "December": "декабря", +} + +var shortMonthNamesRuRU = map[string]string{ + "Jan": "Янв", + "Feb": "Фев", + "Mar": "Мар", + "Apr": "Апр", + "May": "Май", + "Jun": "Июн", + "Jul": "Июл", + "Aug": "Авг", + "Sep": "Сен", + "Oct": "Окт", + "Nov": "Ноя", + "Dec": "Дек", +} + +var shortMonthNamesGenitiveRuRU = map[string]string{ + "Jan": "янв", + "Feb": "фев", + "Mar": "мар", + "Apr": "апр", + "May": "мая", + "Jun": "июн", + "Jul": "июл", + "Aug": "авг", + "Sep": "сен", + "Oct": "окт", + "Nov": "ноя", + "Dec": "дек", +} diff --git a/vendor/github.com/goodsign/monday/format_sl_si.go b/vendor/github.com/goodsign/monday/format_sl_si.go new file mode 100644 index 0000000..6f75b4a --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_sl_si.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "sl_SI" locale: Slovenian +// ============================================================ + +var longDayNamesSlSI = map[string]string{ + "Sunday": "nedelja", + "Monday": "ponedeljek", + "Tuesday": "toret", + "Wednesday": "sreda", + "Thursday": "četrtek", + "Friday": "petek", + "Saturday": "sobota", +} + +var shortDayNamesSlSI = map[string]string{ + "Sun": "ned", + "Mon": "pon", + "Tue": "tor", + "Wed": "sre", + "Thu": "čet", + "Fri": "pet", + "Sat": "sob", +} + +var longMonthNamesSlSI = map[string]string{ + "January": "januar", + "February": "februar", + "March": "marec", + "April": "april", + "May": "maj", + "June": "junij", + "July": "julij", + "August": "avgust", + "September": "september", + "October": "oktober", + "November": "november", + "December": "december", +} + +var shortMonthNamesSlSI = map[string]string{ + "Jan": "jan", + "Feb": "feb", + "Mar": "mar", + "Apr": "apr", + "May": "maj", + "Jun": "jun", + "Jul": "jul", + "Aug": "avg", + "Sep": "sep", + "Oct": "okt", + "Nov": "nov", + "Dec": "dec", +} diff --git a/vendor/github.com/goodsign/monday/format_sv_se.go b/vendor/github.com/goodsign/monday/format_sv_se.go new file mode 100644 index 0000000..b138231 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_sv_se.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "sv_SE" locale: Swedish (Sweden) +// ============================================================ + +var longDayNamesSvSE = map[string]string{ + "Sunday": "söndag", + "Monday": "måndag", + "Tuesday": "tisdag", + "Wednesday": "onsdag", + "Thursday": "torsdag", + "Friday": "fredag", + "Saturday": "lördag", +} + +var shortDayNamesSvSE = map[string]string{ + "Sun": "sön", + "Mon": "mån", + "Tue": "tis", + "Wed": "ons", + "Thu": "tors", + "Fri": "fre", + "Sat": "lör", +} + +var longMonthNamesSvSE = map[string]string{ + "January": "januari", + "February": "februari", + "March": "mars", + "April": "april", + "May": "maj", + "June": "juni", + "July": "juli", + "August": "augusti", + "September": "september", + "October": "oktober", + "November": "november", + "December": "december", +} + +var shortMonthNamesSvSE = map[string]string{ + "Jan": "jan", + "Feb": "feb", + "Mar": "mar", + "Apr": "apr", + "May": "maj", + "Jun": "jun", + "Jul": "jul", + "Aug": "aug", + "Sep": "sep", + "Oct": "okt", + "Nov": "nov", + "Dec": "dec", +} diff --git a/vendor/github.com/goodsign/monday/format_tr_tr.go b/vendor/github.com/goodsign/monday/format_tr_tr.go new file mode 100644 index 0000000..f380390 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_tr_tr.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "tr_TR" locale: Turkish (Turkey) +// ============================================================ + +var longDayNamesTrTR = map[string]string{ + "Sunday": "Pazar", + "Monday": "Pazartesi", + "Tuesday": "Salı", + "Wednesday": "Çarşamba", + "Thursday": "Perşembe", + "Friday": "Cuma", + "Saturday": "Cumartesi", +} + +var shortDayNamesTrTR = map[string]string{ + "Sun": "Paz", + "Mon": "Pzt", + "Tue": "Sal", + "Wed": "Çar", + "Thu": "Per", + "Fri": "Cum", + "Sat": "Cmt", +} + +var longMonthNamesTrTR = map[string]string{ + "January": "Ocak", + "February": "Şubat", + "March": "Mart", + "April": "Nisan", + "May": "Mayıs", + "June": "Haziran", + "July": "Temmuz", + "August": "Ağustos", + "September": "Eylül", + "October": "Ekim", + "November": "Kasım", + "December": "Aralık", +} + +var shortMonthNamesTrTR = map[string]string{ + "Jan": "Oca", + "Feb": "Şub", + "Mar": "Mar", + "Apr": "Nis", + "May": "May", + "Jun": "Haz", + "Jul": "Tem", + "Aug": "Ağu", + "Sep": "Eyl", + "Oct": "Eki", + "Nov": "Kas", + "Dec": "Ara", +} diff --git a/vendor/github.com/goodsign/monday/format_uk_ua.go b/vendor/github.com/goodsign/monday/format_uk_ua.go new file mode 100644 index 0000000..1d3033c --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_uk_ua.go @@ -0,0 +1,85 @@ +package monday + +// ============================================================ +// Format rules for "uk_UA" locale: Ukrainian (Ukraine) +// ============================================================ + +var longDayNamesUkUA = map[string]string{ + "Sunday": "Неділя", + "Monday": "Понеділок", + "Tuesday": "Вівторок", + "Wednesday": "Середа", + "Thursday": "Четвер", + "Friday": "П’ятниця", + "Saturday": "Субота", +} + +var shortDayNamesUkUA = map[string]string{ + "Sun": "Нд", + "Mon": "Пн", + "Tue": "Вт", + "Wed": "Ср", + "Thu": "Чт", + "Fri": "Пт", + "Sat": "Сб", +} + +var longMonthNamesUkUA = map[string]string{ + "January": "Січень", + "February": "Лютий", + "March": "Березень", + "April": "Квітень", + "May": "Травень", + "June": "Червень", + "July": "Липень", + "August": "Серпень", + "September": "Вересень", + "October": "Жовтень", + "November": "Листопад", + "December": "Грудень", +} + +var longMonthNamesGenitiveUkUA = map[string]string{ + "January": "січеня", + "February": "лютого", + "March": "березня", + "April": "квітня", + "May": "травня", + "June": "червня", + "July": "липня", + "August": "серпня", + "September": "вересня", + "October": "жовтня", + "November": "листопада", + "December": "грудня", +} + +var shortMonthNamesUkUA = map[string]string{ + "Jan": "Січ", + "Feb": "Лют", + "Mar": "Бер", + "Apr": "Кві", + "May": "Тра", + "Jun": "Чер", + "Jul": "Лип", + "Aug": "Сер", + "Sep": "Вер", + "Oct": "Жов", + "Nov": "Лис", + "Dec": "Гру", +} + +var shortMonthNamesGenitiveUkUA = map[string]string{ + "Jan": "січ", + "Feb": "лют", + "Mar": "бер", + "Apr": "кві", + "May": "тра", + "Jun": "чер", + "Jul": "лип", + "Aug": "сер", + "Sep": "вер", + "Oct": "жов", + "Nov": "лис", + "Dec": "гру", +} diff --git a/vendor/github.com/goodsign/monday/format_zh_cn.go b/vendor/github.com/goodsign/monday/format_zh_cn.go new file mode 100644 index 0000000..b3ed1d8 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_zh_cn.go @@ -0,0 +1,75 @@ +package monday + +import "strings" + +// ============================================================ +// Format rules for "zh_CN" locale: Chinese (Mainland) +// ============================================================ + +var longDayNamesZhCN = map[string]string{ + "Sunday": "星期日", + "Monday": "星期一", + "Tuesday": "星期二", + "Wednesday": "星期三", + "Thursday": "星期四", + "Friday": "星期五", + "Saturday": "星期六", +} + +var shortDayNamesZhCN = map[string]string{ + "Sun": "日", + "Mon": "一", + "Tue": "二", + "Wed": "三", + "Thu": "四", + "Fri": "五", + "Sat": "六", +} + +var longMonthNamesZhCN = map[string]string{ + "January": "1 月", + "February": "2 月", + "March": "3 月", + "April": "4 月", + "May": "5 月", + "June": "6 月", + "July": "7 月", + "August": "8 月", + "September": "9 月", + "October": "10 月", + "November": "11 月", + "December": "12 月", +} + +var shortMonthNamesZhCN = map[string]string{ + "Jan": "1", + "Feb": "2", + "Mar": "3", + "Apr": "4", + "May": "5", + "Jun": "6", + "Jul": "7", + "Aug": "8", + "Sep": "9", + "Oct": "10", + "Nov": "11", + "Dec": "12", +} + +func parseFuncZhCommon(locale Locale) internalParseFunc { + return func(layout, value string) string { + // This special case is needed because Zh_CN/Zh/HK/... contains month names + // that consist of a number, a delimiter, and '月'. Example: "October" = "10 月" + // + // This means that probably default time package layout IDs like 'January' or 'Jan' + // shouldn't be used in Zh_*. But this is a time-compatible package, so someone + // might actually use those and we need to replace those before doing standard procedures. + for k, v := range knownMonthsLongReverse[locale] { + value = strings.Replace(value, k, v, -1) + } + + return commonFormatFunc(value, layout, + knownDaysShortReverse[locale], knownDaysLongReverse[locale], + knownMonthsShortReverse[locale], knownMonthsLongReverse[locale], knownPeriods[locale]) + } +} diff --git a/vendor/github.com/goodsign/monday/format_zh_hk.go b/vendor/github.com/goodsign/monday/format_zh_hk.go new file mode 100644 index 0000000..45bbb24 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_zh_hk.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "zh_HK" locale: Chinese (Hong Kong) +// ============================================================ + +var longDayNamesZhHK = map[string]string{ + "Sunday": "星期日", + "Monday": "星期一", + "Tuesday": "星期二", + "Wednesday": "星期三", + "Thursday": "星期四", + "Friday": "星期五", + "Saturday": "星期六", +} + +var shortDayNamesZhHK = map[string]string{ + "Sun": "日", + "Mon": "一", + "Tue": "二", + "Wed": "三", + "Thu": "四", + "Fri": "五", + "Sat": "六", +} + +var longMonthNamesZhHK = map[string]string{ + "January": "1 月", + "February": "2 月", + "March": "3 月", + "April": "4 月", + "May": "5 月", + "June": "6 月", + "July": "7 月", + "August": "8 月", + "September": "9 月", + "October": "10 月", + "November": "11 月", + "December": "12 月", +} + +var shortMonthNamesZhHK = map[string]string{ + "Jan": "1", + "Feb": "2", + "Mar": "3", + "Apr": "4", + "May": "5", + "Jun": "6", + "Jul": "7", + "Aug": "8", + "Sep": "9", + "Oct": "10", + "Nov": "11", + "Dec": "12", +} diff --git a/vendor/github.com/goodsign/monday/format_zh_tw.go b/vendor/github.com/goodsign/monday/format_zh_tw.go new file mode 100644 index 0000000..5d6a4d0 --- /dev/null +++ b/vendor/github.com/goodsign/monday/format_zh_tw.go @@ -0,0 +1,55 @@ +package monday + +// ============================================================ +// Format rules for "zh_TW" locale: Chinese (Taiwan) +// ============================================================ + +var longDayNamesZhTW = map[string]string{ + "Sunday": "星期日", + "Monday": "星期一", + "Tuesday": "星期二", + "Wednesday": "星期三", + "Thursday": "星期四", + "Friday": "星期五", + "Saturday": "星期六", +} + +var shortDayNamesZhTW = map[string]string{ + "Sun": "日", + "Mon": "一", + "Tue": "二", + "Wed": "三", + "Thu": "四", + "Fri": "五", + "Sat": "六", +} + +var longMonthNamesZhTW = map[string]string{ + "January": "1 月", + "February": "2 月", + "March": "3 月", + "April": "4 月", + "May": "5 月", + "June": "6 月", + "July": "7 月", + "August": "8 月", + "September": "9 月", + "October": "10 月", + "November": "11 月", + "December": "12 月", +} + +var shortMonthNamesZhTW = map[string]string{ + "Jan": "1", + "Feb": "2", + "Mar": "3", + "Apr": "4", + "May": "5", + "Jun": "6", + "Jul": "7", + "Aug": "8", + "Sep": "9", + "Oct": "10", + "Nov": "11", + "Dec": "12", +} diff --git a/vendor/github.com/goodsign/monday/locale.go b/vendor/github.com/goodsign/monday/locale.go new file mode 100644 index 0000000..6be569e --- /dev/null +++ b/vendor/github.com/goodsign/monday/locale.go @@ -0,0 +1,91 @@ +package monday + +// Locale identifies locales supported by 'monday' package. +// Monday uses ICU locale identifiers. See http://userguide.icu-project.org/locale +type Locale string + +// Locale constants represent all locales that are currently supported by +// this package. +const ( + LocaleEnUS = "en_US" // English (United States) + LocaleEnGB = "en_GB" // English (United Kingdom) + LocaleDaDK = "da_DK" // Danish (Denmark) + LocaleNlBE = "nl_BE" // Dutch (Belgium) + LocaleNlNL = "nl_NL" // Dutch (Netherlands) + LocaleFiFI = "fi_FI" // Finnish (Finland) + LocaleFrFR = "fr_FR" // French (France) + LocaleFrCA = "fr_CA" // French (Canada) + LocaleDeDE = "de_DE" // German (Germany) + LocaleHuHU = "hu_HU" // Hungarian (Hungary) + LocaleItIT = "it_IT" // Italian (Italy) + LocaleNnNO = "nn_NO" // Norwegian Nynorsk (Norway) + LocaleNbNO = "nb_NO" // Norwegian Bokmål (Norway) + LocalePlPL = "pl_PL" // Polish (Poland) + LocalePtPT = "pt_PT" // Portuguese (Portugal) + LocalePtBR = "pt_BR" // Portuguese (Brazil) + LocaleRoRO = "ro_RO" // Romanian (Romania) + LocaleRuRU = "ru_RU" // Russian (Russia) + LocaleEsES = "es_ES" // Spanish (Spain) + LocaleCaES = "ca_ES" // Catalan (Spain) + LocaleSvSE = "sv_SE" // Swedish (Sweden) + LocaleTrTR = "tr_TR" // Turkish (Turkey) + LocaleUkUA = "uk_UA" // Ukrainian (Ukraine) + LocaleBgBG = "bg_BG" // Bulgarian (Bulgaria) + LocaleZhCN = "zh_CN" // Chinese (Mainland) + LocaleZhTW = "zh_TW" // Chinese (Taiwan) + LocaleZhHK = "zh_HK" // Chinese (Hong Kong) + LocaleKoKR = "ko_KR" // Korean (Korea) + LocaleJaJP = "ja_JP" // Japanese (Japan) + LocaleElGR = "el_GR" // Greek (Greece) + LocaleIdID = "id_ID" // Indonesian (Indonesia) + LocaleFrGP = "fr_GP" // French (Guadeloupe) + LocaleFrLU = "fr_LU" // French (Luxembourg) + LocaleFrMQ = "fr_MQ" // French (Martinique) + LocaleFrRE = "fr_RE" // French (Reunion) + LocaleFrGF = "fr_GF" // French (French Guiana) + LocaleCsCZ = "cs_CZ" // Czech (Czech Republic) + LocaleSlSI = "sl_SI" // Slovenian (Slovenia) +) + +// ListLocales returns all locales supported by the package. +func ListLocales() []Locale { + return []Locale{ + LocaleEnUS, + LocaleEnGB, + LocaleDaDK, + LocaleNlBE, + LocaleNlNL, + LocaleFiFI, + LocaleFrFR, + LocaleFrCA, + LocaleDeDE, + LocaleHuHU, + LocaleItIT, + LocaleNnNO, + LocaleNbNO, + LocalePlPL, + LocalePtPT, + LocalePtBR, + LocaleRoRO, + LocaleRuRU, + LocaleEsES, + LocaleCaES, + LocaleSvSE, + LocaleTrTR, + LocaleUkUA, + LocaleBgBG, + LocaleZhCN, + LocaleZhTW, + LocaleZhHK, + LocaleKoKR, + LocaleJaJP, + LocaleElGR, + LocaleFrGP, + LocaleFrLU, + LocaleFrMQ, + LocaleFrRE, + LocaleFrGF, + LocaleCsCZ, + LocaleSlSI, + } +} diff --git a/vendor/github.com/goodsign/monday/monday.go b/vendor/github.com/goodsign/monday/monday.go new file mode 100644 index 0000000..cbcaf27 --- /dev/null +++ b/vendor/github.com/goodsign/monday/monday.go @@ -0,0 +1,563 @@ +package monday + +import ( + "fmt" + "time" +) + +// internalFormatFunc is a preprocessor for default time.Format func +type internalFormatFunc func(value, layout string) string + +var internalFormatFuncs = map[Locale]internalFormatFunc{ + LocaleEnUS: createCommonFormatFunc(LocaleEnUS), + LocaleEnGB: createCommonFormatFunc(LocaleEnGB), + LocaleDaDK: createCommonFormatFunc(LocaleDaDK), + LocaleNlBE: createCommonFormatFunc(LocaleNlBE), + LocaleNlNL: createCommonFormatFunc(LocaleNlNL), + LocaleFrFR: createCommonFormatFunc(LocaleFrFR), + LocaleFrCA: createCommonFormatFunc(LocaleFrFR), + LocaleFrGP: createCommonFormatFunc(LocaleFrFR), + LocaleFrLU: createCommonFormatFunc(LocaleFrFR), + LocaleFrMQ: createCommonFormatFunc(LocaleFrFR), + LocaleFrGF: createCommonFormatFunc(LocaleFrFR), + LocaleFrRE: createCommonFormatFunc(LocaleFrFR), + LocaleRuRU: createCommonFormatFuncWithGenitive(LocaleRuRU), + LocaleFiFI: createCommonFormatFuncWithGenitive(LocaleFiFI), + LocaleDeDE: createCommonFormatFunc(LocaleDeDE), + LocaleHuHU: createCommonFormatFunc(LocaleHuHU), + LocaleItIT: createCommonFormatFunc(LocaleItIT), + LocaleNnNO: createCommonFormatFunc(LocaleNnNO), + LocaleNbNO: createCommonFormatFunc(LocaleNbNO), + LocalePlPL: createCommonFormatFunc(LocalePlPL), + LocalePtPT: createCommonFormatFunc(LocalePtPT), + LocalePtBR: createCommonFormatFunc(LocalePtBR), + LocaleRoRO: createCommonFormatFunc(LocaleRoRO), + LocaleEsES: createCommonFormatFunc(LocaleEsES), + LocaleCaES: createCommonFormatFunc(LocaleCaES), + LocaleSvSE: createCommonFormatFunc(LocaleSvSE), + LocaleTrTR: createCommonFormatFunc(LocaleTrTR), + LocaleUkUA: createCommonFormatFuncWithGenitive(LocaleUkUA), + LocaleBgBG: createCommonFormatFunc(LocaleBgBG), + LocaleZhCN: createCommonFormatFunc(LocaleZhCN), + LocaleZhTW: createCommonFormatFunc(LocaleZhTW), + LocaleZhHK: createCommonFormatFunc(LocaleZhHK), + LocaleKoKR: createCommonFormatFunc(LocaleKoKR), + LocaleJaJP: createCommonFormatFunc(LocaleJaJP), + LocaleElGR: createCommonFormatFuncWithGenitive(LocaleElGR), + LocaleIdID: createCommonFormatFunc(LocaleIdID), + LocaleCsCZ: createCommonFormatFunc(LocaleCsCZ), + LocaleSlSI: createCommonFormatFunc(LocaleSlSI), +} + +// internalParseFunc is a preprocessor for default time.ParseInLocation func +type internalParseFunc func(layout, value string) string + +var internalParseFuncs = map[Locale]internalParseFunc{ + LocaleEnUS: createCommonParseFunc(LocaleEnUS), + LocaleEnGB: createCommonParseFunc(LocaleEnGB), + LocaleDaDK: createCommonParseFunc(LocaleDaDK), + LocaleNlBE: createCommonParseFunc(LocaleNlBE), + LocaleNlNL: createCommonParseFunc(LocaleNlNL), + LocaleFrFR: createCommonParseFunc(LocaleFrFR), + LocaleFrCA: createCommonParseFunc(LocaleFrFR), + LocaleFrGP: createCommonParseFunc(LocaleFrFR), + LocaleFrLU: createCommonParseFunc(LocaleFrFR), + LocaleFrMQ: createCommonParseFunc(LocaleFrFR), + LocaleFrGF: createCommonParseFunc(LocaleFrFR), + LocaleFrRE: createCommonParseFunc(LocaleFrFR), + LocaleRuRU: createCommonParsetFuncWithGenitive(LocaleRuRU), + LocaleFiFI: createCommonParsetFuncWithGenitive(LocaleFiFI), + LocaleDeDE: createCommonParseFunc(LocaleDeDE), + LocaleHuHU: createCommonParseFunc(LocaleHuHU), + LocaleItIT: createCommonParseFunc(LocaleItIT), + LocaleNnNO: createCommonParseFunc(LocaleNnNO), + LocaleNbNO: createCommonParseFunc(LocaleNbNO), + LocalePlPL: parseFuncPtCommon(LocalePlPL), + LocalePtPT: parseFuncPtCommon(LocalePtPT), + LocalePtBR: parseFuncPtCommon(LocalePtBR), + LocaleRoRO: createCommonParseFunc(LocaleRoRO), + LocaleEsES: createCommonParseFunc(LocaleEsES), + LocaleCaES: createCommonParseFunc(LocaleCaES), + LocaleSvSE: createCommonParseFunc(LocaleSvSE), + LocaleTrTR: createCommonParseFunc(LocaleTrTR), + LocaleUkUA: createCommonParsetFuncWithGenitive(LocaleUkUA), + LocaleBgBG: createCommonParseFunc(LocaleBgBG), + LocaleZhCN: parseFuncZhCommon(LocaleZhCN), + LocaleZhTW: parseFuncZhCommon(LocaleZhTW), + LocaleZhHK: parseFuncZhCommon(LocaleZhHK), + LocaleKoKR: parseFuncKoCommon(LocaleKoKR), + LocaleJaJP: parseFuncJaCommon(LocaleJaJP), + LocaleElGR: createCommonParsetFuncWithGenitive(LocaleElGR), + LocaleIdID: createCommonParseFunc(LocaleIdID), + LocaleCsCZ: createCommonParseFunc(LocaleCsCZ), + LocaleSlSI: createCommonParseFunc(LocaleSlSI), +} + +var knownDaysShort = map[Locale]map[string]string{} // Mapping for 'Format', days of week, short form +var knownDaysLong = map[Locale]map[string]string{} // Mapping for 'Format', days of week, long form +var knownMonthsLong = map[Locale]map[string]string{} // Mapping for 'Format', months: long form +var knownMonthsShort = map[Locale]map[string]string{} // Mapping for 'Format', months: short form +var knownMonthsGenitiveShort = map[Locale]map[string]string{} // Mapping for 'Format', special for names in genitive, short form +var knownMonthsGenitiveLong = map[Locale]map[string]string{} // Mapping for 'Format', special for names in genitive, long form +var knownPeriods = map[Locale]map[string]string{} // Mapping for 'Format', AM/PM + +// Reverse maps for the same + +var knownDaysShortReverse = map[Locale]map[string]string{} // Mapping for 'Format', days of week, short form +var knownDaysLongReverse = map[Locale]map[string]string{} // Mapping for 'Format', days of week, long form +var knownMonthsLongReverse = map[Locale]map[string]string{} // Mapping for 'Format', months: long form +var knownMonthsShortReverse = map[Locale]map[string]string{} // Mapping for 'Format', months: short form +var knownMonthsGenitiveShortReverse = map[Locale]map[string]string{} // Mapping for 'Format', special for names in genitive, short form +var knownMonthsGenitiveLongReverse = map[Locale]map[string]string{} // Mapping for 'Format', special for names in genitive, long form +var knownPeriodsReverse = map[Locale]map[string]string{} // Mapping for 'Format', AM/PM + +func init() { + fillKnownWords() +} + +func fillKnownWords() { + + // En_US: English (United States) + fillKnownDaysLong(longDayNamesEnUS, LocaleEnUS) + fillKnownDaysShort(shortDayNamesEnUS, LocaleEnUS) + fillKnownMonthsLong(longMonthNamesEnUS, LocaleEnUS) + fillKnownMonthsShort(shortMonthNamesEnUS, LocaleEnUS) + + // En_GB: English (United Kingdom) + fillKnownDaysLong(longDayNamesEnUS, LocaleEnGB) + fillKnownDaysShort(shortDayNamesEnUS, LocaleEnGB) + fillKnownMonthsLong(longMonthNamesEnUS, LocaleEnGB) + fillKnownMonthsShort(shortMonthNamesEnUS, LocaleEnGB) + + // Da_DK: Danish (Denmark) + fillKnownDaysLong(longDayNamesDaDK, LocaleDaDK) + fillKnownDaysShort(shortDayNamesDaDK, LocaleDaDK) + fillKnownMonthsLong(longMonthNamesDaDK, LocaleDaDK) + fillKnownMonthsShort(shortMonthNamesDaDK, LocaleDaDK) + + // Nl_BE: Dutch (Belgium) + fillKnownDaysLong(longDayNamesNlBE, LocaleNlBE) + fillKnownDaysShort(shortDayNamesNlBE, LocaleNlBE) + fillKnownMonthsLong(longMonthNamesNlBE, LocaleNlBE) + fillKnownMonthsShort(shortMonthNamesNlBE, LocaleNlBE) + + // Nl_NL: Dutch (Netherlands) + fillKnownDaysLong(longDayNamesNlBE, LocaleNlNL) + fillKnownDaysShort(shortDayNamesNlBE, LocaleNlNL) + fillKnownMonthsLong(longMonthNamesNlBE, LocaleNlNL) + fillKnownMonthsShort(shortMonthNamesNlBE, LocaleNlNL) + + // Fi_FI: Finnish (Finland) + fillKnownDaysLong(longDayNamesFiFI, LocaleFiFI) + fillKnownDaysShort(shortDayNamesFiFI, LocaleFiFI) + fillKnownMonthsLong(longMonthNamesFiFI, LocaleFiFI) + fillKnownMonthsShort(shortMonthNamesFiFI, LocaleFiFI) + fillKnownMonthsGenitiveLong(longMonthNamesGenitiveFiFI, LocaleFiFI) + fillKnownMonthsGenitiveShort(shortMonthNamesFiFI, LocaleFiFI) + + // Fr_FR: French (France) + fillKnownDaysLong(longDayNamesFrFR, LocaleFrFR) + fillKnownDaysShort(shortDayNamesFrFR, LocaleFrFR) + fillKnownMonthsLong(longMonthNamesFrFR, LocaleFrFR) + fillKnownMonthsShort(shortMonthNamesFrFR, LocaleFrFR) + + // Fr_CA: French (Canada) + fillKnownDaysLong(longDayNamesFrFR, LocaleFrCA) + fillKnownDaysShort(shortDayNamesFrFR, LocaleFrCA) + fillKnownMonthsLong(longMonthNamesFrFR, LocaleFrCA) + fillKnownMonthsShort(shortMonthNamesFrFR, LocaleFrCA) + + // Fr_GP: French (Guadeloupe) + fillKnownDaysLong(longDayNamesFrFR, LocaleFrGP) + fillKnownDaysShort(shortDayNamesFrFR, LocaleFrGP) + fillKnownMonthsLong(longMonthNamesFrFR, LocaleFrGP) + fillKnownMonthsShort(shortMonthNamesFrFR, LocaleFrGP) + + // Fr_LU: French (Luxembourg) + fillKnownDaysLong(longDayNamesFrFR, LocaleFrLU) + fillKnownDaysShort(longDayNamesFrFR, LocaleFrLU) + fillKnownMonthsLong(longDayNamesFrFR, LocaleFrLU) + fillKnownMonthsShort(longDayNamesFrFR, LocaleFrLU) + + // Fr_MQ: French (Martinique) + fillKnownDaysLong(longDayNamesFrFR, LocaleFrMQ) + fillKnownDaysShort(longDayNamesFrFR, LocaleFrMQ) + fillKnownMonthsLong(longDayNamesFrFR, LocaleFrMQ) + fillKnownMonthsShort(longDayNamesFrFR, LocaleFrMQ) + + // Fr_GF: French (French Guiana) + fillKnownDaysLong(longDayNamesFrFR, LocaleFrGF) + fillKnownDaysShort(longDayNamesFrFR, LocaleFrGF) + fillKnownMonthsLong(longDayNamesFrFR, LocaleFrGF) + fillKnownMonthsShort(longDayNamesFrFR, LocaleFrGF) + + // Fr_RE: French (French Reunion) + fillKnownDaysLong(longDayNamesFrFR, LocaleFrRE) + fillKnownDaysShort(longDayNamesFrFR, LocaleFrRE) + fillKnownMonthsLong(longDayNamesFrFR, LocaleFrRE) + fillKnownMonthsShort(longDayNamesFrFR, LocaleFrRE) + + // De_DE: German (Germany) + fillKnownDaysLong(longDayNamesDeDE, LocaleDeDE) + fillKnownDaysShort(shortDayNamesDeDE, LocaleDeDE) + fillKnownMonthsLong(longMonthNamesDeDE, LocaleDeDE) + fillKnownMonthsShort(shortMonthNamesDeDE, LocaleDeDE) + + // Hu_HU: Hungarian (Hungary) + fillKnownDaysLong(longDayNamesHuHU, LocaleHuHU) + fillKnownDaysShort(shortDayNamesHuHU, LocaleHuHU) + fillKnownMonthsLong(longMonthNamesHuHU, LocaleHuHU) + fillKnownMonthsShort(shortMonthNamesHuHU, LocaleHuHU) + + // It_IT: Italian (Italy) + fillKnownDaysLong(longDayNamesItIT, LocaleItIT) + fillKnownDaysShort(shortDayNamesItIT, LocaleItIT) + fillKnownMonthsLong(longMonthNamesItIT, LocaleItIT) + fillKnownMonthsShort(shortMonthNamesItIT, LocaleItIT) + + // Nn_NO: Norwegian Nynorsk (Norway) + fillKnownDaysLong(longDayNamesNnNO, LocaleNnNO) + fillKnownDaysShort(shortDayNamesNnNO, LocaleNnNO) + fillKnownMonthsLong(longMonthNamesNnNO, LocaleNnNO) + fillKnownMonthsShort(shortMonthNamesNnNO, LocaleNnNO) + + // Nb_NO: Norwegian Bokmål (Norway) + fillKnownDaysLong(longDayNamesNbNO, LocaleNbNO) + fillKnownDaysShort(shortDayNamesNbNO, LocaleNbNO) + fillKnownMonthsLong(longMonthNamesNbNO, LocaleNbNO) + fillKnownMonthsShort(shortMonthNamesNbNO, LocaleNbNO) + + // Pl_PL: Polish (Poland) + fillKnownDaysLong(longDayNamesPlPL, LocalePlPL) + fillKnownDaysShort(shortDayNamesPlPL, LocalePlPL) + fillKnownMonthsLong(longMonthNamesPlPL, LocalePlPL) + fillKnownMonthsShort(shortMonthNamesPlPL, LocalePlPL) + + // Pt_PT: Portuguese (Portugal) + fillKnownDaysLong(longDayNamesPtPT, LocalePtPT) + fillKnownDaysShort(shortDayNamesPtPT, LocalePtPT) + fillKnownMonthsLong(longMonthNamesPtPT, LocalePtPT) + fillKnownMonthsShort(shortMonthNamesPtPT, LocalePtPT) + + // Pt_BR: Portuguese (Brazil) + fillKnownDaysLong(longDayNamesPtBR, LocalePtBR) + fillKnownDaysShort(shortDayNamesPtBR, LocalePtBR) + fillKnownMonthsLong(longMonthNamesPtBR, LocalePtBR) + fillKnownMonthsShort(shortMonthNamesPtBR, LocalePtBR) + + // Ro_RO: Romanian (Romania) + fillKnownDaysLong(longDayNamesRoRO, LocaleRoRO) + fillKnownDaysShort(shortDayNamesRoRO, LocaleRoRO) + fillKnownMonthsLong(longMonthNamesRoRO, LocaleRoRO) + fillKnownMonthsShort(shortMonthNamesRoRO, LocaleRoRO) + + // Ru_RU: Russian (Russia) + fillKnownDaysLong(longDayNamesRuRU, LocaleRuRU) + fillKnownDaysShort(shortDayNamesRuRU, LocaleRuRU) + fillKnownMonthsLong(longMonthNamesRuRU, LocaleRuRU) + fillKnownMonthsShort(shortMonthNamesRuRU, LocaleRuRU) + fillKnownMonthsGenitiveLong(longMonthNamesGenitiveRuRU, LocaleRuRU) + fillKnownMonthsGenitiveShort(shortMonthNamesGenitiveRuRU, LocaleRuRU) + + // Es_ES: Spanish (Spain) + fillKnownDaysLong(longDayNamesEsES, LocaleEsES) + fillKnownDaysShort(shortDayNamesEsES, LocaleEsES) + fillKnownMonthsLong(longMonthNamesEsES, LocaleEsES) + fillKnownMonthsShort(shortMonthNamesEsES, LocaleEsES) + + // Ca_ES: Catalan (Spain) + fillKnownDaysLong(longDayNamesCaES, LocaleCaES) + fillKnownDaysShort(shortDayNamesCaES, LocaleCaES) + fillKnownMonthsLong(longMonthNamesCaES, LocaleCaES) + fillKnownMonthsShort(shortMonthNamesCaES, LocaleCaES) + + // Sv_SE: Swedish (Sweden) + fillKnownDaysLong(longDayNamesSvSE, LocaleSvSE) + fillKnownDaysShort(shortDayNamesSvSE, LocaleSvSE) + fillKnownMonthsLong(longMonthNamesSvSE, LocaleSvSE) + fillKnownMonthsShort(shortMonthNamesSvSE, LocaleSvSE) + + // Tr_TR: Turkish (Turkey) + fillKnownDaysLong(longDayNamesTrTR, LocaleTrTR) + fillKnownDaysShort(shortDayNamesTrTR, LocaleTrTR) + fillKnownMonthsLong(longMonthNamesTrTR, LocaleTrTR) + fillKnownMonthsShort(shortMonthNamesTrTR, LocaleTrTR) + + // Uk_UA: Ukrainian (Ukraine) + fillKnownDaysLong(longDayNamesUkUA, LocaleUkUA) + fillKnownDaysShort(shortDayNamesUkUA, LocaleUkUA) + fillKnownMonthsLong(longMonthNamesUkUA, LocaleUkUA) + fillKnownMonthsShort(shortMonthNamesUkUA, LocaleUkUA) + fillKnownMonthsGenitiveLong(longMonthNamesGenitiveUkUA, LocaleUkUA) + fillKnownMonthsGenitiveShort(shortMonthNamesGenitiveUkUA, LocaleUkUA) + + // Bg_BG: Bulgarian (Bulgaria) + fillKnownDaysLong(longDayNamesBgBG, LocaleBgBG) + fillKnownDaysShort(shortDayNamesBgBG, LocaleBgBG) + fillKnownMonthsLong(longMonthNamesBgBG, LocaleBgBG) + fillKnownMonthsShort(shortMonthNamesBgBG, LocaleBgBG) + + // Zh_CN: Chinese (Mainland) + fillKnownDaysLong(longDayNamesZhCN, LocaleZhCN) + fillKnownDaysShort(shortDayNamesZhCN, LocaleZhCN) + fillKnownMonthsLong(longMonthNamesZhCN, LocaleZhCN) + fillKnownMonthsShort(shortMonthNamesZhCN, LocaleZhCN) + + // Zh_TW: Chinese (Taiwan) + fillKnownDaysLong(longDayNamesZhTW, LocaleZhTW) + fillKnownDaysShort(shortDayNamesZhTW, LocaleZhTW) + fillKnownMonthsLong(longMonthNamesZhTW, LocaleZhTW) + fillKnownMonthsShort(shortMonthNamesZhTW, LocaleZhTW) + + // Zh_HK: Chinese (Hong Kong) + fillKnownDaysLong(longDayNamesZhHK, LocaleZhHK) + fillKnownDaysShort(shortDayNamesZhHK, LocaleZhHK) + fillKnownMonthsLong(longMonthNamesZhHK, LocaleZhHK) + fillKnownMonthsShort(shortMonthNamesZhHK, LocaleZhHK) + + // Ko_KR: Korean (Korea) + fillKnownDaysLong(longDayNamesKoKR, LocaleKoKR) + fillKnownDaysShort(shortDayNamesKoKR, LocaleKoKR) + fillKnownMonthsLong(longMonthNamesKoKR, LocaleKoKR) + fillKnownMonthsShort(shortMonthNamesKoKR, LocaleKoKR) + fillKnownPeriods(periodsKoKR, LocaleKoKR) + + // Ja_JP: Japanese (Japan) + fillKnownDaysLong(longDayNamesJaJP, LocaleJaJP) + fillKnownDaysShort(shortDayNamesJaJP, LocaleJaJP) + fillKnownMonthsLong(longMonthNamesJaJP, LocaleJaJP) + fillKnownMonthsShort(shortMonthNamesJaJP, LocaleJaJP) + fillKnownPeriods(periodsJaJP, LocaleJaJP) + + // El_GR: Greek (Greece) + fillKnownDaysLong(longDayNamesElGR, LocaleElGR) + fillKnownDaysShort(shortDayNamesElGR, LocaleElGR) + fillKnownMonthsLong(longMonthNamesElGR, LocaleElGR) + fillKnownMonthsShort(shortMonthNamesElGR, LocaleElGR) + fillKnownMonthsGenitiveLong(longMonthNamesGenitiveElGR, LocaleElGR) + fillKnownMonthsGenitiveShort(shortMonthNamesElGR, LocaleElGR) + fillKnownPeriods(periodsElGR, LocaleElGR) + + // Id_ID: Indonesia (Indonesia) + fillKnownDaysLong(longDayNamesIdID, LocaleIdID) + fillKnownDaysShort(shortDayNamesIdID, LocaleIdID) + fillKnownMonthsLong(longMonthNamesIdID, LocaleIdID) + fillKnownMonthsShort(shortMonthNamesIdID, LocaleIdID) + + // Cs_CZ: Czech (Czech Republic) + fillKnownDaysLong(longDayNamesCsCZ, LocaleCsCZ) + fillKnownDaysShort(shortDayNamesCsCZ, LocaleCsCZ) + fillKnownMonthsLong(longMonthNamesCsCZ, LocaleCsCZ) + fillKnownMonthsShort(shortMonthNamesCsCZ, LocaleCsCZ) + + // Sl_SI: Slovenian (Slovenia) + fillKnownDaysLong(longDayNamesSlSI, LocaleSlSI) + fillKnownDaysShort(shortDayNamesSlSI, LocaleSlSI) + fillKnownMonthsLong(longMonthNamesSlSI, LocaleSlSI) + fillKnownMonthsShort(shortMonthNamesSlSI, LocaleSlSI) +} + +func fill(src map[string]string, dest map[Locale]map[string]string, locale Locale) { + loc, ok := dest[locale] + + if !ok { + loc = make(map[string]string, len(src)) + dest[locale] = loc + } + + for k, v := range src { + loc[k] = v + } +} + +func fillReverse(src map[string]string, dest map[Locale]map[string]string, locale Locale) { + loc, ok := dest[locale] + + if !ok { + loc = make(map[string]string, len(src)) + dest[locale] = loc + } + + for k, v := range src { + loc[v] = k + } +} + +func fillKnownMonthsGenitiveShort(src map[string]string, locale Locale) { + fillReverse(src, knownMonthsGenitiveShortReverse, locale) + fill(src, knownMonthsGenitiveShort, locale) +} + +func fillKnownMonthsGenitiveLong(src map[string]string, locale Locale) { + fillReverse(src, knownMonthsGenitiveLongReverse, locale) + fill(src, knownMonthsGenitiveLong, locale) +} + +func fillKnownDaysShort(src map[string]string, locale Locale) { + fillReverse(src, knownDaysShortReverse, locale) + fill(src, knownDaysShort, locale) +} + +func fillKnownDaysLong(src map[string]string, locale Locale) { + fillReverse(src, knownDaysLongReverse, locale) + fill(src, knownDaysLong, locale) +} + +func fillKnownMonthsShort(src map[string]string, locale Locale) { + fillReverse(src, knownMonthsShortReverse, locale) + fill(src, knownMonthsShort, locale) +} + +func fillKnownMonthsLong(src map[string]string, locale Locale) { + fillReverse(src, knownMonthsLongReverse, locale) + fill(src, knownMonthsLong, locale) +} + +func fillKnownPeriods(src map[string]string, locale Locale) { + fillReverse(src, knownPeriodsReverse, locale) + fill(src, knownPeriods, locale) +} + +// Format is the standard time.Format wrapper, that replaces known standard 'time' package +// identifiers for months and days to their equivalents in the specified language. +// +// Values of variables 'longDayNames', 'shortDayNames', 'longMonthNames', 'shortMonthNames' +// from file 'time/format.go' (revision 'go1') are chosen as the 'known' words. +// +// Some languages have specific behavior, e.g. in Russian language +// month names have different suffix when they are presented stand-alone (i.e. in a list or something) +// and yet another one when they are part of a formatted date. +// So, even though March is "Март" in Russian, correctly formatted today's date would be: "7 марта 2007". +// Thus, some transformations for some languages may be a bit more complex than just plain replacements. +func Format(dt time.Time, layout string, locale Locale) string { + fm := dt.Format(layout) + intFunc, ok := internalFormatFuncs[locale] + if !ok { + return fm + } + return intFunc(fm, layout) +} + +// ParseInLocation is the standard time.ParseInLocation wrapper, which replaces +// known month/day translations for a specified locale back to English before +// calling time.ParseInLocation. So, you can parse localized dates with this wrapper. +func ParseInLocation(layout, value string, loc *time.Location, locale Locale) (time.Time, error) { + intFunc, ok := internalParseFuncs[locale] + if ok { + value = intFunc(layout, value) + } else { + return time.Now(), fmt.Errorf("unsupported locale: %v", locale) + } + + return time.ParseInLocation(layout, value, loc) +} + +// Parse is the standard time.Parse wrapper, which replaces +// known month/day translations for a specified locale back to English before +// calling time.Parse. +func Parse(layout, value string, locale Locale) (time.Time, error) { + intFunc, ok := internalParseFuncs[locale] + if ok { + value = intFunc(layout, value) + } else { + return time.Now(), fmt.Errorf("unsupported locale: %v", locale) + } + + return time.Parse(layout, value) +} + +// GetShortDays retrieves the list of days for the given locale. +// "Short" days are abbreviated versions of the full day names. In English, +// for example, this might return "Tues" for "Tuesday". For certain locales, +// the long and short form of the days of the week may be the same. +// +// If the locale cannot be found, the resulting slice will be nil. +func GetShortDays(locale Locale) []string { + days, ok := knownDaysShort[locale] + if !ok { + return nil + } + + var dayOrder []string + + // according to https://www.timeanddate.com/calendar/days/monday.html + // only Canada, USA and Japan use Sunday as first day of the week + switch locale { + case LocaleEnUS, LocaleJaJP: + dayOrder = dayShortOrderSundayFirst + default: + dayOrder = dayShortOrderMondayFirst + } + + ret := make([]string, 0, len(days)) + for _, day := range dayOrder { + ret = append(ret, days[day]) + } + return ret +} + +// GetShortMonths retrieves the list of months for the given locale. +// "Short" months are abbreviated versions of the full month names. In +// English, for example, this might return "Jan" for "January". For +// certain locales, the long and short form of the months may be the same. +// +// If the locale cannot be found, the resulting slice will be nil. +func GetShortMonths(locale Locale) []string { + months, ok := knownMonthsShort[locale] + if !ok { + return nil + } + + ret := make([]string, 0, len(months)) + for _, m := range monthShortOrder { + ret = append(ret, months[m]) + } + return ret +} + +// GetLongDays retrieves the list of days for the given locale. It will return +// the full name of the days of the week. +// +// If the locale cannot be found, the resulting slice will be nil. +func GetLongDays(locale Locale) []string { + days, ok := knownDaysLong[locale] + if !ok { + return nil + } + + var dayOrder []string + + // according to https://www.timeanddate.com/calendar/days/monday.html + // only Canada, USA and Japan use Sunday as first day of the week + switch locale { + case LocaleEnUS, LocaleJaJP: + dayOrder = dayLongOrderSundayFirst + default: + dayOrder = dayLongOrderMondayFirst + } + + ret := make([]string, 0, len(days)) + for _, day := range dayOrder { + ret = append(ret, days[day]) + } + return ret +} + +// GetLongMonths retrieves the list of months for the given locale. In +// contrast to the "short" version of this function, this functions returns +// the full name of the month. +// +// If the locale cannot be found, the resulting slice will be nil. +func GetLongMonths(locale Locale) []string { + months, ok := knownMonthsLong[locale] + if !ok { + return nil + } + + ret := make([]string, 0, len(months)) + for _, m := range monthLongOrder { + ret = append(ret, months[m]) + } + + return ret +} diff --git a/vendor/github.com/goodsign/monday/set.go b/vendor/github.com/goodsign/monday/set.go new file mode 100644 index 0000000..fcd6cd9 --- /dev/null +++ b/vendor/github.com/goodsign/monday/set.go @@ -0,0 +1,67 @@ +package monday + +import "sync" + +var keyExists = struct{}{} + +// Set is a thread safe set data structure. +// +// It is ported from https://github.com/fatih/set with only the required functionality. +type set struct { + m map[Locale]struct{} + l sync.RWMutex +} + +// NewSet allocates and returns a new Set. It accepts a variable number of +// arguments to populate the initial set. If nothing is passed a Set with zero +// size is created. +func newSet(items ...Locale) *set { + s := set{ + m: make(map[Locale]struct{}), + } + s.Add(items...) + return &s +} + +// Add adds the specified items (one or more) to the set. The underlying +// Set s is modified. If no items are passed it silently returns. +func (s *set) Add(items ...Locale) { + if len(items) == 0 { + return + } + s.l.Lock() + defer s.l.Unlock() + for _, item := range items { + s.m[item] = keyExists + } +} + +// Each traverses the items in the Set, calling the provided function f for +// each set member. Traversal will continue until all items in the Set have +// been visited, or if the closure returns false. +func (s *set) Each(f func(item Locale) bool) { + s.l.RLock() + defer s.l.RUnlock() + for item := range s.m { + if !f(item) { + break + } + } +} + +// Has looks for the existence of items passed. It returns false if nothing is +// passed. For multiple items it returns true only if all of the items exist. +func (s *set) Has(items ...Locale) bool { + if len(items) == 0 { + return false + } + s.l.RLock() + defer s.l.RUnlock() + has := true + for _, item := range items { + if _, has = s.m[item]; !has { + break + } + } + return has +} diff --git a/vendor/github.com/goodsign/monday/utils_layout.go b/vendor/github.com/goodsign/monday/utils_layout.go new file mode 100644 index 0000000..e41f7cf --- /dev/null +++ b/vendor/github.com/goodsign/monday/utils_layout.go @@ -0,0 +1,92 @@ +package monday + +import ( + "strings" + "unicode" + "unicode/utf8" +) + +// dateStringLayoutItem represents one word or set of delimiters between words. +// This is an abstraction level above date raw character string of date representation. +// +// Example: "1 February / 2013" -> +// dateStringLayoutItem { item: "1", isWord: true } +// dateStringLayoutItem { item: " ", isWord: false } +// dateStringLayoutItem { item: "February", isWord: true } +// dateStringLayoutItem { item: " / ", isWord: false } +// dateStringLayoutItem { item: "2013", isWord: true } +type dateStringLayoutItem struct { + item string + isWord bool // true if this is a sequence of letters/digits (as opposed to a sequence of non-letters like delimiters) + isDigit bool // true if this is a sequence only containing digits +} + +// extractLetterSequence extracts first word (sequence of letters ending with a non-letter) +// starting with the specified index and wraps it to dateStringLayoutItem according to the type +// of the word. +func extractLetterSequence(originalStr string, index int) (it dateStringLayoutItem) { + letters := &strings.Builder{} + + bytesToParse := []byte(originalStr[index:]) + runeCount := utf8.RuneCount(bytesToParse) + + var isWord bool + var isDigit bool + + letters.Grow(runeCount) + for i := 0; i < runeCount; i++ { + rne, runeSize := utf8.DecodeRune(bytesToParse) + bytesToParse = bytesToParse[runeSize:] + + if i == 0 { + isWord = unicode.IsLetter(rne) + isDigit = unicode.IsDigit(rne) + } else { + if (isWord && (!unicode.IsLetter(rne) && !unicode.IsDigit(rne))) || + (isDigit && !unicode.IsDigit(rne)) || + (!isWord && unicode.IsLetter(rne)) || + (!isDigit && unicode.IsDigit(rne)) { + break + } + } + + letters.WriteRune(rne) + } + + it.item = letters.String() + it.isWord = isWord + it.isDigit = isDigit + return +} + +// stringToLayoutItems transforms raw date string (like "2 Mar 2012") into +// a set of dateStringLayoutItems, which are more convenient to work with +// in other analysis modules. +func stringToLayoutItems(dateStr string) (seqs []dateStringLayoutItem) { + i := 0 + + for i < len(dateStr) { + seq := extractLetterSequence(dateStr, i) + i += len(seq.item) + seqs = append(seqs, seq) + } + + return +} + +func layoutToString(li []dateStringLayoutItem) string { + // This function is expensive enough to be worth counting + // bytes and allocating all in one go. + numChars := 0 + for _, v := range li { + numChars += len(v.item) + } + + sb := &strings.Builder{} + sb.Grow(numChars) + for _, v := range li { + sb.WriteString(v.item) + } + + return sb.String() +} diff --git a/vendor/modules.txt b/vendor/modules.txt index abc7a03..5eb7635 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -41,6 +41,9 @@ github.com/go-toast/toast # github.com/godbus/dbus/v5 v5.0.4 ## explicit; go 1.12 github.com/godbus/dbus/v5 +# github.com/goodsign/monday v1.0.0 +## explicit; go 1.13 +github.com/goodsign/monday # github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1 ## explicit github.com/gopherjs/gopherjs/js From 11bf5e23df64cac68400077a1c828a8c037a7f8f Mon Sep 17 00:00:00 2001 From: Simon Roberts Date: Thu, 7 Oct 2021 08:06:58 +1100 Subject: [PATCH 2/6] Start working on locale-sensitive date-time formatting --- pkg/humanize/humanize.go | 56 +++++++++++++++++++++++++++++++++++ pkg/humanize/humanize_test.go | 9 ++++++ 2 files changed, 65 insertions(+) diff --git a/pkg/humanize/humanize.go b/pkg/humanize/humanize.go index 1d45354..5b3901b 100644 --- a/pkg/humanize/humanize.go +++ b/pkg/humanize/humanize.go @@ -6,7 +6,9 @@ import ( "os" "strconv" "strings" + "time" + "github.com/goodsign/monday" "golang.org/x/text/language" "golang.org/x/text/message" ) @@ -29,6 +31,60 @@ func Monetaryf(value float64, precision int) string { 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. +// LANGUAGE +// LC_ALL Will override the setting of all other LC_* variables. +// LC_MONETARY Sets the locale for the LC_MONETARY category. +// LC_NUMERIC Sets the locale for the LC_NUMERIC category. +// LC_TIME Sets the locale for the LC_TIME category. +// 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] +func DetectLocale(usage string) string { + if lc, ok := os.LookupEnv("LANGUAGE"); ok { + return lc + } + if lc, ok := os.LookupEnv("LC_ALL"); ok { + return lc + } + if usage != "" { + if lc, ok := os.LookupEnv(strings.ToUpper(usage)); ok { + return lc + } + } + if lc, ok := os.LookupEnv("LANG"); ok { + return lc + } + return "C" +} + +// func DetectLanguage(usage string) language.Tag { +// lc := DetectLocale(usage) +// if lc == "C" { +// lc = "en" +// } +// return language.Make(lc) +// } + +// Locale is language[_territory][.codeset] [@modifier] +func FormatTime(time time.Time, layout string) string { + // Attempt to use the environment to determine monday.Locale + 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 // separator according to language found in given locale environment variable e. // If fixed is true the decimal places are fixed to the given precision otherwise d is the diff --git a/pkg/humanize/humanize_test.go b/pkg/humanize/humanize_test.go index 4051382..981f8eb 100644 --- a/pkg/humanize/humanize_test.go +++ b/pkg/humanize/humanize_test.go @@ -3,6 +3,7 @@ package humanize import ( "fmt" "testing" + "time" ) // TestMonetary tests monetary formatting @@ -51,3 +52,11 @@ func TestScaleNumeric(t *testing.T) { } } } + +func TestFormatTime(t *testing.T) { + s := FormatTime(time.Now(), "Jan 2006") + t.Logf("First: %s", s) + if Monetaryf(834142.3256, 2) != "834,142.3256" { + t.FailNow() + } +} From 1cf12fd1731ff4b089ac5af0a8abaade7960cd74 Mon Sep 17 00:00:00 2001 From: Simon Roberts Date: Fri, 8 Oct 2021 08:36:00 +1100 Subject: [PATCH 3/6] Add github.com/jeandeaual/go-locale for locale-detection across platform --- go.mod | 1 + go.sum | 29 +++ .../jeandeaual/go-locale/.gitattributes | 1 + .../jeandeaual/go-locale/.gitignore | 44 ++++ .../jeandeaual/go-locale/.golangci.yml | 40 +++ .../github.com/jeandeaual/go-locale/LICENSE | 21 ++ .../github.com/jeandeaual/go-locale/README.md | 135 ++++++++++ .../jeandeaual/go-locale/locale_android.c | 243 ++++++++++++++++++ .../jeandeaual/go-locale/locale_android.go | 115 +++++++++ .../jeandeaual/go-locale/locale_darwin.go | 95 +++++++ .../jeandeaual/go-locale/locale_ios.go | 51 ++++ .../jeandeaual/go-locale/locale_ios.m | 17 ++ .../jeandeaual/go-locale/locale_js.go | 75 ++++++ .../jeandeaual/go-locale/locale_unix.go | 116 +++++++++ .../jeandeaual/go-locale/locale_windows.go | 101 ++++++++ .../github.com/jeandeaual/go-locale/util.go | 27 ++ vendor/modules.txt | 3 + 17 files changed, 1114 insertions(+) create mode 100644 vendor/github.com/jeandeaual/go-locale/.gitattributes create mode 100644 vendor/github.com/jeandeaual/go-locale/.gitignore create mode 100644 vendor/github.com/jeandeaual/go-locale/.golangci.yml create mode 100644 vendor/github.com/jeandeaual/go-locale/LICENSE create mode 100644 vendor/github.com/jeandeaual/go-locale/README.md create mode 100644 vendor/github.com/jeandeaual/go-locale/locale_android.c create mode 100644 vendor/github.com/jeandeaual/go-locale/locale_android.go create mode 100644 vendor/github.com/jeandeaual/go-locale/locale_darwin.go create mode 100644 vendor/github.com/jeandeaual/go-locale/locale_ios.go create mode 100644 vendor/github.com/jeandeaual/go-locale/locale_ios.m create mode 100644 vendor/github.com/jeandeaual/go-locale/locale_js.go create mode 100644 vendor/github.com/jeandeaual/go-locale/locale_unix.go create mode 100644 vendor/github.com/jeandeaual/go-locale/locale_windows.go create mode 100644 vendor/github.com/jeandeaual/go-locale/util.go diff --git a/go.mod b/go.mod index 06fa77d..f4fc8c6 100644 --- a/go.mod +++ b/go.mod @@ -11,6 +11,7 @@ require ( github.com/gen2brain/beeep v0.0.0-20210529141713-5586760f0cc1 github.com/gliderlabs/ssh v0.3.3 github.com/goodsign/monday v1.0.0 + github.com/jeandeaual/go-locale v0.0.0-20210323163322-5cf4ff553a8d github.com/maruel/panicparse v1.6.1 github.com/mattn/go-runewidth v0.0.13 github.com/miguelmota/go-coinmarketcap v0.1.8 diff --git a/go.sum b/go.sum index 8da5023..b727224 100644 --- a/go.sum +++ b/go.sum @@ -37,13 +37,16 @@ cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohl cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs= cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +fyne.io/fyne v1.4.2/go.mod h1:xL4c3WmpE/Tvz5CEm5vqsaizU/EeOCm9DYlL2GtTSiM= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.4.1 h1:GaI7EiDXDRfa8VshkTj7Fym7ha+y8/XxIgD2okUIjLw= github.com/BurntSushi/toml v0.4.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/Kodeworks/golang-image-ico v0.0.0-20141118225523-73f0f4cfade9/go.mod h1:7uhhqiBaR4CpN0k9rMjOtjpcfGd6DG2m04zQxKnWQ0I= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d h1:licZJFw2RwpHMqeKTCYkitsPqHNxTmd4SNR5r94FGM8= github.com/acarl005/stripansi v0.0.0-20180116102854-5a71ef0e047d/go.mod h1:asat636LX7Bqt5lYEZ27JNDcqxfjdBQuJ/MM4CN/Lzo= +github.com/akavel/rsrc v0.8.0/go.mod h1:uLoCtb9J+EyAqh+26kdrTgmzRBFPGOolLWKpdxkKq+c= github.com/anaskhan96/soup v1.0.1 h1:3p9zOr7o2weHqDakRA1uR0SZNr6VhH5qPkm6p3gvS6o= github.com/anaskhan96/soup v1.0.1/go.mod h1:pT5vs4HXDwA5y4KQCsKvnkpQd3D+joP7IqpiGskfWW0= github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= @@ -84,6 +87,8 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w= github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk= github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ= +github.com/fyne-io/mobile v0.1.2-0.20201127155338-06aeb98410cc/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= +github.com/fyne-io/mobile v0.1.2/go.mod h1:/kOrWrZB6sasLbEy2JIvr4arEzQTXBTZGb3Y96yWbHY= github.com/gdamore/encoding v1.0.0/go.mod h1:alR0ol34c49FCSBLjhosxzcPHQbf2trDkoo5dl+VrEg= github.com/gdamore/tcell v1.3.0/go.mod h1:Hjvr+Ofd+gLglo7RYKxxnzCBmev3BzsS67MebKS4zMM= github.com/gen2brain/beeep v0.0.0-20210529141713-5586760f0cc1 h1:Xh9mvwEmhbdXlRSsgn+N0zj/NqnKvpeqL08oKDHln2s= @@ -91,15 +96,18 @@ github.com/gen2brain/beeep v0.0.0-20210529141713-5586760f0cc1/go.mod h1:ElSskYZe github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04= github.com/gliderlabs/ssh v0.3.3 h1:mBQ8NiOgDkINJrZtoizkC3nDNYgSaWtxyem6S2XHBtA= github.com/gliderlabs/ssh v0.3.3/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= +github.com/go-gl/gl v0.0.0-20190320180904-bf2b1f2f34d7/go.mod h1:482civXOzJJCPzJ4ZOX/pwvXBWSnzD4OKMdH4ClKGbk= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200625191551-73d3c3675aa3/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 h1:qZNfIGkIANxGv/OqtnntR4DfOY2+BgwR60cAcu/i3SE= github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4/go.mod h1:kW3HQ4UdaAyrUCSSDR4xUzBKW6O2iA4uHhk7AtyYp10= github.com/godbus/dbus/v5 v5.0.3/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/godbus/dbus/v5 v5.0.4 h1:9349emZab16e7zQvpmsbtjc18ykshndd8y2PG3sgJbA= github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/goki/freetype v0.0.0-20181231101311-fa8a33aabaff/go.mod h1:wfqRWLHRBsRgkp5dmbG56SA0DmVtwrF5N3oPdI8t+Aw= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= @@ -194,6 +202,10 @@ github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1: github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/jackmordaunt/icns v0.0.0-20181231085925-4f16af745526/go.mod h1:UQkeMHVoNcyXYq9otUupF7/h/2tmHlhrS2zw7ZVvUqc= +github.com/jeandeaual/go-locale v0.0.0-20210323163322-5cf4ff553a8d h1:VPBM6qn7uSBJroH61nL9yqtfK0xDWcmI5JHl11a2CJ0= +github.com/jeandeaual/go-locale v0.0.0-20210323163322-5cf4ff553a8d/go.mod h1:S0Hh9Ro1RbEQKfJA5XcnmGjcSQF+ZdSVikXVNQJMTAo= +github.com/josephspurrier/goversioninfo v0.0.0-20200309025242-14b0ab84c6ca/go.mod h1:eJTEwMjXb7kZ633hO3Ln9mBUCOjX2+FlTljvpl9SYdE= github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= @@ -206,6 +218,7 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/lucasb-eyer/go-colorful v1.0.2/go.mod h1:0MS4r+7BZKSJ5mw4/S5MPN+qHFF1fYclkSPilDOKW0s= github.com/lucasb-eyer/go-colorful v1.0.3/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/lucor/goinfo v0.0.0-20200401173949-526b5363a13a/go.mod h1:ORP3/rB5IsulLEBwQZCJyyV6niqmI7P4EWSmkug+1Ng= github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPKd5NZ3oSwXrF60= github.com/maruel/panicparse v1.6.1 h1:803MjBzGcUgE1vYgg3UMNq3G1oyYeKkMu3t6hBS97x0= github.com/maruel/panicparse v1.6.1/go.mod h1:uoxI4w9gJL6XahaYPMq/z9uadrdr1SyHuQwV2q80Mm0= @@ -245,6 +258,9 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +github.com/nicksnyder/go-i18n/v2 v2.1.1/go.mod h1:d++QJC9ZVf7pa48qrsRWhMJ5pSHIPmS3OLqK1niyLxs= +github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= @@ -253,7 +269,9 @@ github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FI github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pelletier/go-toml v1.9.3/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCkoOuaOx1Y+c= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/sftp v1.10.1/go.mod h1:lYOWFsE0bwd1+KfKJaKeuokY15vzFx25BLbzYYoAxZI= github.com/pmezard/go-difflib v0.0.0-20151028094244-d8ed2627bdf0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -275,14 +293,18 @@ github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/afero v1.6.0/go.mod h1:Ai8FlHk4v/PARR026UzYexafAt9roJ7LcLMAmO6Z93I= github.com/spf13/cast v1.3.1/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= github.com/spf13/cobra v1.2.1 h1:+KmjbUw1hriSNMF55oPrkZcb27aECyrj8V2ytv7kWDw= github.com/spf13/cobra v1.2.1/go.mod h1:ExllRjgxM/piMAM+3tAZvg8fsklGAf3tPfi+i8t68Nk= github.com/spf13/jwalterweatherman v1.1.0/go.mod h1:aNWZUN0dPAAO/Ljvb5BEdw96iTZ0EXowPYD95IqWIGo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/spf13/viper v1.8.1/go.mod h1:o0Pch8wJ9BVSWGQMbra6iw0oQ5oktSIBaujf1rJH9Ns= +github.com/srwiley/oksvg v0.0.0-20200311192757-870daf9aa564/go.mod h1:afMbS0qvv1m5tfENCwnOdZGOF8RGR/FsZ7bvBxQGZG4= +github.com/srwiley/rasterx v0.0.0-20200120212402-85cb7272f5e9/go.mod h1:mvWM0+15UqyrFKqdRjY6LuAVJR0HOVhJlEgZ5JWtSWU= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v0.0.0-20161117074351-18a02ba4a312/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -337,6 +359,7 @@ golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EH golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/image v0.0.0-20200430140353-33d19683fad8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= @@ -451,12 +474,14 @@ golang.org/x/sys v0.0.0-20200501052902-10377860bb8e/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200511232937-7e40ca221e25/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200515095857-1151b9dac4a9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200523222454-059865788121/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200720211630-cb9d2d5c5666/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200724161237-0e2f3a69832c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200803210538-64077c9b5642/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201223074533-0d417f636930/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -497,6 +522,7 @@ golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBn golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190808195139-e713427fea3f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= @@ -518,6 +544,7 @@ golang.org/x/tools v0.0.0-20200224181240-023911ca70b2/go.mod h1:TB2adYChydJhpapK golang.org/x/tools v0.0.0-20200227222343-706bc42d1f0d/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= golang.org/x/tools v0.0.0-20200304193943-95d2e580d8eb/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= golang.org/x/tools v0.0.0-20200312045724-11d5b4c81c7d/go.mod h1:o4KQGtdN14AW+yjsvvwRTJJuXz8XRtIHtEnmAXLyFUw= +golang.org/x/tools v0.0.0-20200328031815-3db5fc6bac03/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200331025713-a30bf2db82d4/go.mod h1:Sl4aGygMT6LrqrWclx+PTx3U+LnKx/seiNR+3G19Ar8= golang.org/x/tools v0.0.0-20200501065659-ab2804fb9c9d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= @@ -643,11 +670,13 @@ google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp0 google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20200227125254-8fa46927fb4f/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/ini.v1 v1.62.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo= diff --git a/vendor/github.com/jeandeaual/go-locale/.gitattributes b/vendor/github.com/jeandeaual/go-locale/.gitattributes new file mode 100644 index 0000000..fcadb2c --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/.gitattributes @@ -0,0 +1 @@ +* text eol=lf diff --git a/vendor/github.com/jeandeaual/go-locale/.gitignore b/vendor/github.com/jeandeaual/go-locale/.gitignore new file mode 100644 index 0000000..d8d2b9d --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/.gitignore @@ -0,0 +1,44 @@ +### Go ### +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib + +# Test binary, built with `go test -c` +*.test + +# Output of the go coverage tool +*.out + +# Fyne Cross build folder +fyne-cross/ + +### Linux ### +*~ + +### Vim ### +# Swap +[._]*.s[a-v][a-z] +[._]*.sw[a-p] +[._]s[a-rt-v][a-z] +[._]ss[a-gi-z] +[._]sw[a-p] + +# Session +Session.vim + +# Auto-generated tag files +tags + +# Persistent undo +[._]*.un~ + +### VisualStudioCode ### +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +.history diff --git a/vendor/github.com/jeandeaual/go-locale/.golangci.yml b/vendor/github.com/jeandeaual/go-locale/.golangci.yml new file mode 100644 index 0000000..8db7dab --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/.golangci.yml @@ -0,0 +1,40 @@ +run: + timeout: 5m +linters: + disable-all: true + enable: + # Default + - deadcode + - errcheck + - gosimple + - govet + - ineffassign + - staticcheck + - structcheck + - typecheck + - unused + - varcheck + # Manually enabled + - dupl + - gocyclo + - gofmt + - golint + - goprintffuncname + - lll + - misspell + - nakedret + - prealloc + - unconvert + - whitespace +linter-settings: + gocyclo: + # Minimal code complexity to report, 30 by default + min-complexity: 15 + govet: + # Report about shadowed variables + check-shadowing: true +issues: + exclude-use-default: false + exclude: + # govet: Common false positives + - (possible misuse of unsafe.Pointer|should have signature) diff --git a/vendor/github.com/jeandeaual/go-locale/LICENSE b/vendor/github.com/jeandeaual/go-locale/LICENSE new file mode 100644 index 0000000..0278773 --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2020 Alexis Jeandeau + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/vendor/github.com/jeandeaual/go-locale/README.md b/vendor/github.com/jeandeaual/go-locale/README.md new file mode 100644 index 0000000..9562718 --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/README.md @@ -0,0 +1,135 @@ +# go-locale + +[![PkgGoDev](https://pkg.go.dev/badge/github.com/jeandeaual/go-locale)](https://pkg.go.dev/github.com/jeandeaual/go-locale) +[![Go Report Card](https://goreportcard.com/badge/github.com/jeandeaual/go-locale)](https://goreportcard.com/report/github.com/jeandeaual/go-locale) +[![Coverage Status](https://coveralls.io/repos/github/jeandeaual/go-locale/badge.svg?branch=master)](https://coveralls.io/github/jeandeaual/go-locale?branch=master) +[![test](https://github.com/jeandeaual/go-locale/workflows/test/badge.svg)](https://github.com/jeandeaual/go-locale/actions?query=workflow%3Atest) + +Go library used to retrieve the current locale(s) of the operating system. + +## OS Support + +* Windows\ + Using [`GetUserDefaultLocaleName`](https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserdefaultlocalename) and [`GetSystemDefaultLocaleName`](https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultlocalename). +* macOS\ + Using `defaults read -g AppleLocale` and `defaults read -g AppleLanguages` (since environment variables like `LANG` are not usually set on macOS). +* Unix-like systems (Linux, BSD, etc.)\ + Using the `LANGUAGE`, `LC_ALL`, `LC_MESSAGES` and `LANG` environment variables. +* WASM (JavaScript)\ + Using [`navigator.language`](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/language) and [`navigator.languages`](https://developer.mozilla.org/en-US/docs/Web/API/NavigatorLanguage/languages). +* iOS\ + Using [`[NSLocale preferredLanguages]`](https://developer.apple.com/documentation/foundation/nslocale/1415614-preferredlanguages). +* Android\ + Using [`getResources().getConfiguration().getLocales`](https://developer.android.com/reference/android/content/res/Configuration#getLocales()) for Android N or later, or [`getResources().getConfiguration().locale`](https://developer.android.com/reference/android/content/res/Configuration#locale) otherwise. + + Note: for Android, you'll first need to call `SetRunOnJVM`, depending on which mobile framework you're using: + * For [Fyne](https://fyne.io/): + + ```go + import ( + "github.com/fyne-io/mobile/app" + "github.com/jeandeaual/go-locale" + ) + + func init() { + locale.SetRunOnJVM(app.RunOnJVM) + } + ``` + + * For [gomobile](https://github.com/golang/go/wiki/Mobile): + + ```go + import ( + "golang.org/x/mobile/app" + "github.com/jeandeaual/go-locale" + ) + + func init() { + locale.SetRunOnJVM(app.RunOnJVM) + } + ``` + +## Usage + +## GetLocales + +`GetLocales` returns the user's preferred locales, by order of preference, as a slice of [IETF BCP 47 language tag](https://tools.ietf.org/rfc/bcp/bcp47.txt) (e.g. `[]string{"en-US", "fr-FR", "ja-JP"}`). + +This works if the user set multiple languages on macOS and other Unix systems. +Otherwise, it returns a slice with a single locale. + +```go +userLocales, err := locale.GetLocales() +if err == nil { + fmt.Println("Locales:", userLocales) +} +``` + +This can be used with [golang.org/x/text](https://godoc.org/golang.org/x/text) or [go-i18n](https://github.com/nicksnyder/go-i18n) to set the localizer's language preferences: + +```go +import ( + "github.com/jeandeaual/go-locale" + "golang.org/x/text/message" +) + +func main() { + userLocales, _ := locale.GetLocales() + p := message.NewPrinter(message.MatchLanguage(userLocales...)) + ... +} +``` + +```go +import ( + "github.com/jeandeaual/go-locale" + "github.com/nicksnyder/go-i18n/v2/i18n" + "golang.org/x/text/language" +) + +func main() { + userLocales, _ := locale.GetLocales() + bundle := i18n.NewBundle(language.English) + localizer := i18n.NewLocalizer(bundle, userLocales...) + ... +} +``` + +For a complete example, see [here](examples/getlocale-gui/main.go). + +## GetLocale + +`GetLocale` returns the current locale as defined in [IETF BCP 47](https://tools.ietf.org/rfc/bcp/bcp47.txt) (e.g. `"en-US"`). + +```go +userLocale, err := locale.GetLocale() +if err == nil { + fmt.Println("Locale:", userLocale) +} +``` + +## GetLanguage + +`GetLanguage` returns the current language as an [ISO 639](http://en.wikipedia.org/wiki/ISO_639) language code (e.g. `"en"`). + +```go +userLanguage, err := locale.GetLanguage() +if err == nil { + fmt.Println("Language:", userLocale) +} +``` + +## GetRegion + +`GetRegion` returns the current language as an [ISO 3166](http://en.wikipedia.org/wiki/ISO_3166-1) country code (e.g. `"US"`). + +```go +userRegion, err := locale.GetRegion() +if err == nil { + fmt.Println("Region:", userRegion) +} +``` + +## Aknowledgements + +Inspired by [jibber_jabber](https://github.com/cloudfoundry-attic/jibber_jabber). diff --git a/vendor/github.com/jeandeaual/go-locale/locale_android.c b/vendor/github.com/jeandeaual/go-locale/locale_android.c new file mode 100644 index 0000000..94593a4 --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/locale_android.c @@ -0,0 +1,243 @@ +// +build android + +#include +#include +#include +#include + +#define LOG_FATAL(...) __android_log_print(ANDROID_LOG_FATAL, "GoLog", __VA_ARGS__) + +static const char *jstringToCharCopy(JNIEnv *env, const jstring string) +{ + const char *chars = (*env)->GetStringUTFChars(env, string, NULL); + const char *copy = strdup(chars); + (*env)->ReleaseStringUTFChars(env, string, chars); + + return copy; +} + +static jclass findClass(JNIEnv *env, const char *class_name) +{ + jclass clazz = (*env)->FindClass(env, class_name); + + if (clazz == NULL) + { + (*env)->ExceptionClear(env); + LOG_FATAL("cannot find %s", class_name); + return NULL; + } + + return clazz; +} + +static jmethodID findMethod(JNIEnv *env, jclass clazz, const char *name, const char *sig) +{ + jmethodID m = (*env)->GetMethodID(env, clazz, name, sig); + + if (m == 0) + { + (*env)->ExceptionClear(env); + LOG_FATAL("cannot find method %s %s", name, sig); + return 0; + } + + return m; +} + +static jfieldID findField(JNIEnv *env, jclass clazz, const char *name, const char *sig) +{ + jfieldID f = (*env)->GetFieldID(env, clazz, name, sig); + + if (f == 0) + { + (*env)->ExceptionClear(env); + LOG_FATAL("cannot find method %s %s", name, sig); + return 0; + } + + return f; +} + +static jfieldID getStaticFieldID(JNIEnv *env, jclass clazz, const char *name, const char *sig) +{ + jfieldID f = (*env)->GetStaticFieldID(env, clazz, name, sig); + + if (f == 0) + { + (*env)->ExceptionClear(env); + LOG_FATAL("cannot find static field %s %s", name, sig); + return 0; + } + + return f; +} + +static const char *toLanguageTag(JNIEnv *env, jobject locale) +{ + const jclass java_util_Locale = findClass(env, "java/util/Locale"); + + const jstring localeStr = + (*env)->CallObjectMethod( + env, + locale, + (*env)->GetMethodID(env, java_util_Locale, "toLanguageTag", "()Ljava/lang/String;")); + + return jstringToCharCopy(env, localeStr); +} + +static const char *toLanguageTags(JNIEnv *env, jobject locales, jclass android_os_LocaleList) +{ + const jstring localeStr = + (*env)->CallObjectMethod( + env, + locales, + (*env)->GetMethodID(env, android_os_LocaleList, "toLanguageTags", "()Ljava/lang/String;")); + + return jstringToCharCopy(env, localeStr); +} + +static int getAPIVersion(JNIEnv *env) +{ + // VERSION is a nested class within android.os.Build (hence "$" rather than "/") + const jclass versionClass = findClass(env, "android/os/Build$VERSION"); + const jfieldID sdkIntFieldID = getStaticFieldID(env, versionClass, "SDK_INT", "I"); + + int sdkInt = (*env)->GetStaticIntField(env, versionClass, sdkIntFieldID); + + return sdkInt; +} + +static const jobject getConfiguration(JNIEnv *env, jobject context) +{ + const jclass android_content_ContextWrapper = findClass(env, "android/content/ContextWrapper"); + const jclass android_content_res_Resources = findClass(env, "android/content/res/Resources"); + + const jobject resources = + (*env)->CallObjectMethod( + env, + context, + findMethod(env, android_content_ContextWrapper, "getResources", "()Landroid/content/res/Resources;")); + const jobject configuration = + (*env)->CallObjectMethod( + env, + resources, + findMethod(env, android_content_res_Resources, "getConfiguration", "()Landroid/content/res/Configuration;")); + + return configuration; +} + +static const jobject getLocaleObject(JNIEnv *env, jobject context) +{ + const jobject configuration = getConfiguration(env, context); + const jclass android_content_res_Configuration = findClass(env, "android/content/res/Configuration"); + + int version = getAPIVersion(env); + + // Android N or later + // See https://developer.android.com/reference/android/content/res/Configuration#locale + if (version >= 24) { + const jclass android_os_LocaleList = findClass(env, "android/os/LocaleList"); + + const jobject locales = + (*env)->CallObjectMethod( + env, + configuration, + findMethod(env, android_content_res_Configuration, "getLocales", "()Landroid/os/LocaleList;")); + + return (*env)->CallObjectMethod( + env, + locales, + findMethod(env, android_os_LocaleList, "get", "(I)Ljava/util/Locale;"), + 0); + } else { + return (*env)->GetObjectField( + env, + configuration, + findField(env, android_content_res_Configuration, "locale", "Ljava/util/Locale;")); + } +} + +// Basically the same as `getResources().getConfiguration().getLocales()` for Android N and later, +// or `getResources().getConfiguration().locale` for earlier Android version. +const char *getLocales(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx) +{ + JavaVM *vm = (JavaVM *)java_vm; + JNIEnv *env = (JNIEnv *)jni_env; + jobject context = (jobject)ctx; + + const jobject configuration = getConfiguration(env, context); + const jclass android_content_res_Configuration = findClass(env, "android/content/res/Configuration"); + + int version = getAPIVersion(env); + + // Android N or later + // See https://developer.android.com/reference/android/content/res/Configuration#locale + if (version >= 24) { + const jclass android_os_LocaleList = findClass(env, "android/os/LocaleList"); + + const jobject locales = + (*env)->CallObjectMethod( + env, + configuration, + findMethod(env, android_content_res_Configuration, "getLocales", "()Landroid/os/LocaleList;")); + + return toLanguageTags(env, locales, android_os_LocaleList); + } else { + const jobject locale = + (*env)->GetObjectField( + env, + configuration, + findField(env, android_content_res_Configuration, "locale", "Ljava/util/Locale;")); + + return toLanguageTag(env, locale); + } +} + +// Basically the same as `getResources().getConfiguration().getLocales().get(0).toString()` for Android N and later, +// or `getResources().getConfiguration().locale` for earlier Android version. +const char *getLocale(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx) +{ + JavaVM *vm = (JavaVM *)java_vm; + JNIEnv *env = (JNIEnv *)jni_env; + jobject context = (jobject)ctx; + + const jobject locale = getLocaleObject(env, context); + + return toLanguageTag(env, locale); +} + +const char *getLanguage(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx) +{ + JavaVM *vm = (JavaVM *)java_vm; + JNIEnv *env = (JNIEnv *)jni_env; + jobject context = (jobject)ctx; + + const jobject locale = getLocaleObject(env, context); + const jclass java_util_Locale = findClass(env, "java/util/Locale"); + + const jstring language = + (*env)->CallObjectMethod( + env, + locale, + (*env)->GetMethodID(env, java_util_Locale, "getLanguage", "()Ljava/lang/String;")); + + return jstringToCharCopy(env, language); +} + +const char *getRegion(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx) +{ + JavaVM *vm = (JavaVM *)java_vm; + JNIEnv *env = (JNIEnv *)jni_env; + jobject context = (jobject)ctx; + + const jobject locale = getLocaleObject(env, context); + const jclass java_util_Locale = findClass(env, "java/util/Locale"); + + const jstring country = + (*env)->CallObjectMethod( + env, + locale, + (*env)->GetMethodID(env, java_util_Locale, "getCountry", "()Ljava/lang/String;")); + + return jstringToCharCopy(env, country); +} diff --git a/vendor/github.com/jeandeaual/go-locale/locale_android.go b/vendor/github.com/jeandeaual/go-locale/locale_android.go new file mode 100644 index 0000000..b4d1e0b --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/locale_android.go @@ -0,0 +1,115 @@ +// +build android + +package locale + +/* +#cgo LDFLAGS: -landroid -llog + +#include + +const char *getLocales(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx); +const char *getLocale(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx); +const char *getLanguage(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx); +const char *getRegion(uintptr_t java_vm, uintptr_t jni_env, uintptr_t ctx); +*/ +import "C" +import ( + "errors" + "strings" + "unsafe" +) + +var ( + errRunOnJVMNotSet error = errors.New("you first need to call SetRunOnJVM") + runOnJVM func(fn func(vm, env, ctx uintptr) error) error +) + +// SetRunOnJVM sets the RunOnJVM function that will be called by this library. +// This can either be "golang.org/x/mobile/app".RunOnJVM or "github.com/fyne-io/mobile/app".RunOnJVM, +// depending on the mobile framework you're using (both can't be imported at the same time). +// +// RunOnJVM runs fn on a new goroutine locked to an OS thread with a JNIEnv. +// +// RunOnJVM blocks until the call to fn is complete. Any Java +// exception or failure to attach to the JVM is returned as an error. +// +// The function fn takes vm, the current JavaVM*, +// env, the current JNIEnv*, and +// ctx, a jobject representing the global android.context.Context. +func SetRunOnJVM(fn func(fn func(vm, env, ctx uintptr) error) error) { + runOnJVM = fn +} + +// GetLocale retrieves the IETF BCP 47 language tag set on the system. +func GetLocale() (string, error) { + if runOnJVM == nil { + return "", errRunOnJVMNotSet + } + + locale := "" + + err := runOnJVM(func(vm, env, ctx uintptr) error { + chars := C.getLocale(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx)) + locale = C.GoString(chars) + C.free(unsafe.Pointer(chars)) + return nil + }) + + return locale, err +} + +// GetLocales retrieves the IETF BCP 47 language tags set on the system. +func GetLocales() ([]string, error) { + if runOnJVM == nil { + return nil, errRunOnJVMNotSet + } + + locales := "" + + err := runOnJVM(func(vm, env, ctx uintptr) error { + chars := C.getLocales(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx)) + locales = C.GoString(chars) + C.free(unsafe.Pointer(chars)) + return nil + }) + + return strings.Split(locales, ","), err +} + +// GetLanguage retrieves the IETF BCP 47 language tag set on the system and +// returns the language part of the tag. +func GetLanguage() (string, error) { + if runOnJVM == nil { + return "", errRunOnJVMNotSet + } + + language := "" + + err := runOnJVM(func(vm, env, ctx uintptr) error { + chars := C.getLanguage(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx)) + language = C.GoString(chars) + C.free(unsafe.Pointer(chars)) + return nil + }) + + return language, err +} + +// GetRegion retrieves the IETF BCP 47 language tag set on the system and +// returns the region part of the tag. +func GetRegion() (string, error) { + if runOnJVM == nil { + return "", errRunOnJVMNotSet + } + + region := "" + + err := runOnJVM(func(vm, env, ctx uintptr) error { + chars := C.getRegion(C.uintptr_t(vm), C.uintptr_t(env), C.uintptr_t(ctx)) + region = C.GoString(chars) + C.free(unsafe.Pointer(chars)) + return nil + }) + + return region, err +} diff --git a/vendor/github.com/jeandeaual/go-locale/locale_darwin.go b/vendor/github.com/jeandeaual/go-locale/locale_darwin.go new file mode 100644 index 0000000..41c7865 --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/locale_darwin.go @@ -0,0 +1,95 @@ +// +build darwin,!ios + +package locale + +import ( + "fmt" + "os/exec" + "regexp" + "strings" + "syscall" +) + +func execCommand(cmd string, args ...string) (status int, out []byte, err error) { + status = -1 + command := exec.Command(cmd, args...) + + // Execute the command and get the standard and error outputs + out, err = command.CombinedOutput() + if err != nil { + return + } + + // Check the status code + if w, ok := command.ProcessState.Sys().(syscall.WaitStatus); ok { + status = w.ExitStatus() + } + + return +} + +// GetLocale retrieves the IETF BCP 47 language tag set on the system. +func GetLocale() (string, error) { + _, output, err := execCommand("defaults", "read", "-g", "AppleLocale") + if err != nil { + return "", fmt.Errorf("cannot determine locale: %v (output: %s)", err, output) + } + + return strings.TrimRight(strings.Replace(string(output), "_", "-", 1), "\n"), nil +} + +// appleLanguagesRegex is used to parse the output of "defaults read -g AppleLanguages" +// e.g.: +// ( +// "en-US", +// "fr-FR", +// "ja-JP" +// ) +var appleLanguagesRegex = regexp.MustCompile(`"([a-z]{2}-[A-Z]{2})"`) + +// GetLocales retrieves the IETF BCP 47 language tags set on the system. +func GetLocales() ([]string, error) { + _, output, err := execCommand("defaults", "read", "-g", "AppleLanguages") + if err != nil { + return nil, fmt.Errorf("cannot determine locale: %v (output: %s)", err, output) + } + + matches := appleLanguagesRegex.FindAllStringSubmatch(string(output), -1) + if len(matches) == 0 { + return nil, fmt.Errorf("invalid output from \"defaults read -g AppleLanguages\": %s", output) + } + + locales := make([]string, 0, len(matches)) + + for _, match := range matches { + locales = append(locales, match[1]) + } + + return locales, nil +} + +// GetLanguage retrieves the IETF BCP 47 language tag set on the system and +// returns the language part of the tag. +func GetLanguage() (string, error) { + language := "" + + locale, err := GetLocale() + if err == nil { + language, _ = splitLocale(locale) + } + + return language, err +} + +// GetRegion retrieves the IETF BCP 47 language tag set on the system and +// returns the region part of the tag. +func GetRegion() (string, error) { + region := "" + + locale, err := GetLocale() + if err == nil { + _, region = splitLocale(locale) + } + + return region, err +} diff --git a/vendor/github.com/jeandeaual/go-locale/locale_ios.go b/vendor/github.com/jeandeaual/go-locale/locale_ios.go new file mode 100644 index 0000000..6f7e496 --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/locale_ios.go @@ -0,0 +1,51 @@ +// +build ios + +package locale + +/* +#cgo CFLAGS: -x objective-c +#cgo LDFLAGS: -framework Foundation -framework UIKit + +const char *getLocale(); +const char *getLocales(); +*/ +import "C" +import ( + "strings" +) + +// GetLocale retrieves the IETF BCP 47 language tag set on the system. +func GetLocale() (string, error) { + return C.GoString(C.getLocale()), nil +} + +// GetLocales retrieves the IETF BCP 47 language tags set on the system. +func GetLocales() ([]string, error) { + return strings.Split(C.GoString(C.getLocales()), ","), nil +} + +// GetLanguage retrieves the IETF BCP 47 language tag set on the system and +// returns the language part of the tag. +func GetLanguage() (string, error) { + language := "" + + locale, err := GetLocale() + if err == nil { + language, _ = splitLocale(locale) + } + + return language, err +} + +// GetRegion retrieves the IETF BCP 47 language tag set on the system and +// returns the region part of the tag. +func GetRegion() (string, error) { + region := "" + + locale, err := GetLocale() + if err == nil { + _, region = splitLocale(locale) + } + + return region, err +} diff --git a/vendor/github.com/jeandeaual/go-locale/locale_ios.m b/vendor/github.com/jeandeaual/go-locale/locale_ios.m new file mode 100644 index 0000000..684a6ea --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/locale_ios.m @@ -0,0 +1,17 @@ +// +build ios + +#import + +const char *getLocale() +{ + NSString *locale = [[NSLocale preferredLanguages] firstObject]; + + return [locale UTF8String]; +} + +const char *getLocales() +{ + NSString *locales = [[NSLocale preferredLanguages] componentsJoinedByString:@","]; + + return [locales UTF8String]; +} diff --git a/vendor/github.com/jeandeaual/go-locale/locale_js.go b/vendor/github.com/jeandeaual/go-locale/locale_js.go new file mode 100644 index 0000000..5b208aa --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/locale_js.go @@ -0,0 +1,75 @@ +// +build js,wasm + +package locale + +import ( + "errors" + "syscall/js" +) + +func getNavigatorObject() js.Value { + return js.Global().Get("navigator") +} + +// GetLocale retrieves the IETF BCP 47 language tag set on the system. +func GetLocale() (string, error) { + navigator := getNavigatorObject() + if navigator.IsUndefined() { + return "", errors.New("couldn't get window.navigator") + } + + language := navigator.Get("language") + if language.IsUndefined() { + return "", errors.New("couldn't get window.navigator.language") + } + + return language.String(), nil +} + +// GetLocales retrieves the IETF BCP 47 language tags set on the system. +func GetLocales() ([]string, error) { + navigator := getNavigatorObject() + if navigator.IsUndefined() { + return nil, errors.New("couldn't get window.navigator") + } + + languages := navigator.Get("languages") + if languages.IsUndefined() { + return nil, errors.New("couldn't get window.navigator.languages") + } + + locales := make([]string, 0, languages.Length()) + + // Convert the Javascript object to a string slice + for i := 0; i < languages.Length(); i++ { + locales = append(locales, languages.Index(i).String()) + } + + return locales, nil +} + +// GetLanguage retrieves the IETF BCP 47 language tag set on the system and +// returns the language part of the tag. +func GetLanguage() (string, error) { + language := "" + + locale, err := GetLocale() + if err == nil { + language, _ = splitLocale(locale) + } + + return language, err +} + +// GetRegion retrieves the IETF BCP 47 language tag set on the system and +// returns the region part of the tag. +func GetRegion() (string, error) { + region := "" + + locale, err := GetLocale() + if err == nil { + _, region = splitLocale(locale) + } + + return region, err +} diff --git a/vendor/github.com/jeandeaual/go-locale/locale_unix.go b/vendor/github.com/jeandeaual/go-locale/locale_unix.go new file mode 100644 index 0000000..330bb1f --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/locale_unix.go @@ -0,0 +1,116 @@ +// +build !windows,!darwin,!js,!android + +package locale + +import ( + "os" + "strings" +) + +func splitLocales(locales string) []string { + // If the user set different locales, they might be set in $LANGUAGE, + // separated by a colon + return strings.Split(locales, ":") +} + +func getLangFromEnv() string { + locale := "" + + // Check the following environment variables for the language information + // See https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html + for _, env := range [...]string{"LC_ALL", "LC_MESSAGES", "LANG"} { + locale = os.Getenv(env) + if len(locale) > 0 { + break + } + } + + if locale == "C" || locale == "POSIX" { + return locale + } + + // Check LANGUAGE if localization is enabled (not set to "C") + // See https://www.gnu.org/software/gettext/manual/html_node/The-LANGUAGE-variable.html#The-LANGUAGE-variable + languages := os.Getenv("LANGUAGE") + if len(languages) > 0 { + return languages + } + + return locale +} + +func getUnixLocales() []string { + locale := getLangFromEnv() + if locale == "C" || locale == "POSIX" || len(locale) == 0 { + return nil + } + + return splitLocales(locale) +} + +// GetLocale retrieves the IETF BCP 47 language tag set on the system. +func GetLocale() (string, error) { + unixLocales := getUnixLocales() + if unixLocales == nil { + return "", nil + } + + language, region := splitLocale(unixLocales[0]) + locale := language + if len(region) > 0 { + locale = strings.Join([]string{language, region}, "-") + } + + return locale, nil +} + +// GetLocales retrieves the IETF BCP 47 language tags set on the system. +func GetLocales() ([]string, error) { + unixLocales := getUnixLocales() + if unixLocales == nil { + return nil, nil + } + + locales := make([]string, 0, len(unixLocales)) + + for _, unixLocale := range unixLocales { + language, region := splitLocale(unixLocale) + locale := language + if len(region) > 0 { + locale = strings.Join([]string{language, region}, "-") + } + locales = append(locales, locale) + } + + return locales, nil +} + +// GetLanguage retrieves the IETF BCP 47 language tag set on the system and +// returns the language part of the tag. +func GetLanguage() (string, error) { + language := "" + + unixLocales := getUnixLocales() + if unixLocales == nil { + return "", nil + } + + language, _ = splitLocale(unixLocales[0]) + + return language, nil +} + +// GetRegion retrieves the IETF BCP 47 language tag set on the system and +// returns the region part of the tag. +func GetRegion() (string, error) { + region := "" + + unixLocales := getUnixLocales() + if unixLocales == nil { + return "", nil + } + + _, region = splitLocale(unixLocales[0]) + + return region, nil +} diff --git a/vendor/github.com/jeandeaual/go-locale/locale_windows.go b/vendor/github.com/jeandeaual/go-locale/locale_windows.go new file mode 100644 index 0000000..9fd8ab2 --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/locale_windows.go @@ -0,0 +1,101 @@ +// +build windows + +package locale + +import ( + "fmt" + "unsafe" + + "golang.org/x/sys/windows" +) + +// LocaleNameMaxLength is the maximum length of a locale name on Windows. +// See https://docs.microsoft.com/en-us/windows/win32/intl/locale-name-constants. +const LocaleNameMaxLength uint32 = 85 + +func getWindowsLocaleFromProc(syscall string) (string, error) { + dll, err := windows.LoadDLL("kernel32") + if err != nil { + return "", fmt.Errorf("could not find the kernel32 DLL: %v", err) + } + + proc, err := dll.FindProc(syscall) + if err != nil { + return "", fmt.Errorf("could not find the %s proc in kernel32: %v", syscall, err) + } + + buffer := make([]uint16, LocaleNameMaxLength) + + // See https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserdefaultlocalename + // and https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultlocalename + // GetUserDefaultLocaleName and GetSystemDefaultLocaleName both take a buffer and a buffer size, + // and return the length of the locale name (0 if not found). + ret, _, err := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(LocaleNameMaxLength)) + if ret == 0 { + return "", fmt.Errorf("locale not found when calling %s: %v", syscall, err) + } + + return windows.UTF16ToString(buffer), nil +} + +func getWindowsLocale() (string, error) { + var ( + locale string + err error + ) + + for _, proc := range [...]string{"GetUserDefaultLocaleName", "GetSystemDefaultLocaleName"} { + locale, err = getWindowsLocaleFromProc(proc) + if err == nil { + return locale, err + } + } + + return locale, err +} + +// GetLocale retrieves the IETF BCP 47 language tag set on the system. +func GetLocale() (string, error) { + locale, err := getWindowsLocale() + if err != nil { + return "", fmt.Errorf("cannot determine locale: %v", err) + } + + return locale, err +} + +// GetLocales retrieves the IETF BCP 47 language tags set on the system. +func GetLocales() ([]string, error) { + locale, err := GetLocale() + if err != nil { + return nil, err + } + + return []string{locale}, nil +} + +// GetLanguage retrieves the IETF BCP 47 language tag set on the system and +// returns the language part of the tag. +func GetLanguage() (string, error) { + language := "" + + locale, err := GetLocale() + if err == nil { + language, _ = splitLocale(locale) + } + + return language, err +} + +// GetRegion retrieves the IETF BCP 47 language tag set on the system and +// returns the region part of the tag. +func GetRegion() (string, error) { + region := "" + + locale, err := GetLocale() + if err == nil { + _, region = splitLocale(locale) + } + + return region, err +} diff --git a/vendor/github.com/jeandeaual/go-locale/util.go b/vendor/github.com/jeandeaual/go-locale/util.go new file mode 100644 index 0000000..6638511 --- /dev/null +++ b/vendor/github.com/jeandeaual/go-locale/util.go @@ -0,0 +1,27 @@ +// +build !android + +package locale + +import ( + "strings" +) + +// SetRunOnJVM is a noop, this function is only valid on Android +func SetRunOnJVM(fn func(fn func(vm, env, ctx uintptr) error) error) {} + +func splitLocale(locale string) (string, string) { + // Remove the encoding, if present + formattedLocale := strings.Split(locale, ".")[0] + // Normalize by replacing the hyphens with underscores + formattedLocale = strings.Replace(formattedLocale, "-", "_", -1) + + // Split at the underscore + split := strings.Split(formattedLocale, "_") + language := split[0] + territory := "" + if len(split) > 1 { + territory = split[1] + } + + return language, territory +} diff --git a/vendor/modules.txt b/vendor/modules.txt index 5eb7635..cbc9c0d 100644 --- a/vendor/modules.txt +++ b/vendor/modules.txt @@ -53,6 +53,9 @@ github.com/gopherjs/gopherwasm/js # github.com/inconshreveable/mousetrap v1.0.0 ## explicit github.com/inconshreveable/mousetrap +# github.com/jeandeaual/go-locale v0.0.0-20210323163322-5cf4ff553a8d +## explicit; go 1.12 +github.com/jeandeaual/go-locale # github.com/maruel/panicparse v1.6.1 ## explicit; go 1.11 github.com/maruel/panicparse/stack From 9e910402f540d2e9c3994f086c5c4922a15b3c12 Mon Sep 17 00:00:00 2001 From: Simon Roberts Date: Fri, 8 Oct 2021 11:20:11 +1100 Subject: [PATCH 4/6] New method to format date-time in locale and LC_TIME sensitive way --- pkg/humanize/humanize.go | 94 ++++++++++++++++++----------------- pkg/humanize/humanize_test.go | 40 +++++++++++++-- 2 files changed, 85 insertions(+), 49 deletions(-) diff --git a/pkg/humanize/humanize.go b/pkg/humanize/humanize.go index 5b3901b..ad486a7 100644 --- a/pkg/humanize/humanize.go +++ b/pkg/humanize/humanize.go @@ -9,10 +9,13 @@ import ( "time" "github.com/goodsign/monday" + "github.com/jeandeaual/go-locale" "golang.org/x/text/language" "golang.org/x/text/message" ) +var cachedSystemLocale = "" + // 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 // 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) } -// Attempt to determine the locale from the current environment. If usage is provided, treat it as the name of a LC_xxx environment variable. -// LANGUAGE -// LC_ALL Will override the setting of all other LC_* variables. -// LC_MONETARY Sets the locale for the LC_MONETARY category. -// LC_NUMERIC Sets the locale for the LC_NUMERIC category. -// LC_TIME Sets the locale for the LC_TIME category. -// 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] -func DetectLocale(usage string) string { - if lc, ok := os.LookupEnv("LANGUAGE"); ok { - return lc - } - if lc, ok := os.LookupEnv("LC_ALL"); ok { - return lc - } - if usage != "" { - if lc, ok := os.LookupEnv(strings.ToUpper(usage)); ok { - return lc - } +// borrowed from go-locale/util.go +func splitLocale(locale string) (string, string) { + // Remove the encoding, if present + formattedLocale := strings.Split(locale, ".")[0] + // Normalize by replacing the hyphens with underscores + formattedLocale = strings.Replace(formattedLocale, "-", "_", -1) + + // Split at the underscore + split := strings.Split(formattedLocale, "_") + language := split[0] + territory := "" + if len(split) > 1 { + territory = split[1] } - if lc, ok := os.LookupEnv("LANG"); ok { - return lc - } - return "C" -} -// func DetectLanguage(usage string) language.Tag { -// lc := DetectLocale(usage) -// if lc == "C" { -// lc = "en" -// } -// return language.Make(lc) -// } + return language, territory +} -// Locale is language[_territory][.codeset] [@modifier] -func FormatTime(time time.Time, layout string) string { - // Attempt to use the environment to determine monday.Locale - 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 +// 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}, "-") + } + } else { + // Then use (cached) system-specific locale + if cachedSystemLocale == "" { + if loc, err := locale.GetLocale(); err == nil { + userLocale = loc + cachedSystemLocale = loc } + } else { + userLocale = cachedSystemLocale } } + return userLocale +} + +// formatTimeExplicit formats the given time using the prescribed layout with the provided userLocale +func formatTimeExplicit(time time.Time, layout string, userLocale string) string { + mondayLocale := monday.Locale(strings.Replace(userLocale, "-", "_", 1)) + return monday.Format(time, layout, mondayLocale) +} - return monday.Format(time, layout, locale) +// FormatTime is a dropin replacement time.Format(layout) that uses system locale + LC_TIME +func FormatTime(time time.Time, layout string) string { + return formatTimeExplicit(time, layout, getLocale("LC_TIME")) } // f formats given value, with precision decimal places using thousands and decimal diff --git a/pkg/humanize/humanize_test.go b/pkg/humanize/humanize_test.go index 981f8eb..f24bae5 100644 --- a/pkg/humanize/humanize_test.go +++ b/pkg/humanize/humanize_test.go @@ -54,9 +54,41 @@ func TestScaleNumeric(t *testing.T) { } func TestFormatTime(t *testing.T) { - s := FormatTime(time.Now(), "Jan 2006") - t.Logf("First: %s", s) - if Monetaryf(834142.3256, 2) != "834,142.3256" { - t.FailNow() + testData := map[string]map[string]string{ + "en_GB": { + "Monday 2 January 2006": "Wednesday 12 March 2014", + "Jan 2006": "Mar 2014", + "02 Jan 2006": "12 Mar 2014", + "02/01/2006": "12/03/2014", + }, + "en_US": { + "Monday 2 January 2006": "Wednesday 12 March 2014", + "Jan 2006": "Mar 2014", + "02 Jan 2006": "12 Mar 2014", + "02/01/2006": "12/03/2014", // ?? + }, + "fr_FR": { + "Monday 2 January 2006": "mercredi 12 mars 2014", + "Jan 2006": "mars 2014", + "02 Jan 2006": "12 mars 2014", + "02/01/2006": "12/03/2014", + }, + "de_DE": { + "Monday 2 January 2006": "Mittwoch 12 März 2014", + "Jan 2006": "Mär 2014", + "02 Jan 2006": "12 Mär 2014", + "02/01/2006": "12/03/2014", + }, + } + + testTime := time.Date(2014, 3, 12, 0, 0, 0, 0, time.Local) + for locale, tests := range testData { + for layout, result := range tests { + s := formatTimeExplicit(testTime, layout, locale) + if s != result { + t.Fatalf("Expected layout '%s' in locale %s to render '%s' but got '%s'", layout, locale, result, s) + } + + } } } From aece7676086df010ae3494f49b769c8ff5a67325 Mon Sep 17 00:00:00 2001 From: Simon Roberts Date: Fri, 8 Oct 2021 11:26:35 +1100 Subject: [PATCH 5/6] Use new FormatTime for X-axis labels and last_updated --- cointop/coins_table.go | 2 +- cointop/portfolio.go | 2 +- pkg/timedata/timedata.go | 5 ++++- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/cointop/coins_table.go b/cointop/coins_table.go index 79dff1b..d0d2a40 100644 --- a/cointop/coins_table.go +++ b/cointop/coins_table.go @@ -291,7 +291,7 @@ func (ct *Cointop) GetCoinsTable() *table.Table { }) case "last_updated": unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64) - lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02") + lastUpdated := humanize.FormatTime(time.Unix(unix, 0), "15:04:05 Jan 02") ct.SetTableColumnWidthFromString(header, lastUpdated) ct.SetTableColumnAlignLeft(header, false) rowCells = append(rowCells, diff --git a/cointop/portfolio.go b/cointop/portfolio.go index 722c217..89f6077 100644 --- a/cointop/portfolio.go +++ b/cointop/portfolio.go @@ -290,7 +290,7 @@ func (ct *Cointop) GetPortfolioTable() *table.Table { }) case "last_updated": unix, _ := strconv.ParseInt(coin.LastUpdated, 10, 64) - lastUpdated := time.Unix(unix, 0).Format("15:04:05 Jan 02") + lastUpdated := humanize.FormatTime(time.Unix(unix, 0), "15:04:05 Jan 02") ct.SetTableColumnWidthFromString(header, lastUpdated) ct.SetTableColumnAlignLeft(header, false) rowCells = append(rowCells, diff --git a/pkg/timedata/timedata.go b/pkg/timedata/timedata.go index 8e25ded..e04074b 100644 --- a/pkg/timedata/timedata.go +++ b/pkg/timedata/timedata.go @@ -4,6 +4,8 @@ import ( "math" "sort" "time" + + "github.com/cointop-sh/cointop/pkg/humanize" ) // ResampleTimeSeriesData resamples the given [timestamp,value] data to numsteps between start-end (returns numSteps+1 points). @@ -59,7 +61,8 @@ func BuildTimeSeriesLabels(data [][]float64) []string { } var labels []string for i := range data { - labels = append(labels, time.UnixMilli(int64(data[i][0])).Format(timeFormat)) + labelTime := time.UnixMilli(int64(data[i][0])) + labels = append(labels, humanize.FormatTime(labelTime, timeFormat)) } return labels } From 1713392f08038baf3c7a878950642c14c9784c84 Mon Sep 17 00:00:00 2001 From: Simon Roberts Date: Fri, 8 Oct 2021 11:46:50 +1100 Subject: [PATCH 6/6] Update comment --- pkg/humanize/humanize.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/humanize/humanize.go b/pkg/humanize/humanize.go index ad486a7..975a1d1 100644 --- a/pkg/humanize/humanize.go +++ b/pkg/humanize/humanize.go @@ -53,7 +53,7 @@ func splitLocale(locale string) (string, string) { } // 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. +// The envvar provided is checked first (eg LC_TIME), before the platform-specific defaults. func getLocale(envvar string) string { userLocale := "en-US" // default language-REGION // First try looking up envar directly