From 5a64c076438f6007d34ac5b11bb12c8a1cbfd696 Mon Sep 17 00:00:00 2001 From: Dogacel Date: Fri, 15 Jun 2018 23:51:08 +0300 Subject: [PATCH 1/3] Started implementing language options. --- language.go | 26 ++++++++++++++++++++++++++ locals/en_US.ruleset | 30 ++++++++++++++++++++++++++++++ locals/tr_TR.ruleset | 24 ++++++++++++++++++++++++ ordinals.go | 1 + 4 files changed, 81 insertions(+) create mode 100644 language.go create mode 100644 locals/en_US.ruleset create mode 100644 locals/tr_TR.ruleset diff --git a/language.go b/language.go new file mode 100644 index 0000000..94cb7a5 --- /dev/null +++ b/language.go @@ -0,0 +1,26 @@ +package humanize + +// Local type for the ordinals and times. +type Local string + +// Local for constant language values +const ( + English Local = "en_US" + Turkish Local = "tr_TR" +) + +var active = English + +// GetLanguage of the humanizing option. +func GetLanguage() Local { + return active +} + +// SetLanguage of the humanizing option. +func SetLanguage(l Local) { + active = l +} + +func ParseRuleset(l Local) { + +} diff --git a/locals/en_US.ruleset b/locals/en_US.ruleset new file mode 100644 index 0000000..2dbe7fb --- /dev/null +++ b/locals/en_US.ruleset @@ -0,0 +1,30 @@ +#magnitudes + now: "now" + 1_second: "1 second" + seconds: "%d seconds" + 1_minute: "1 minute" + minutes: "%d minutes" + 1_hour: "1 hour" + hours: "%d hours" + 1_day: "1 day" + days: "%d days" + 1_week: "1 week" + weeks: "%d weeks" + 1_month: "1 month" + months: "%d months" + 1_year: "1 year" + years: "%d years" + longtime: "a long while" + +#indicators + before: "ago" suffix + later: "from now" suffix + +#ordinals + %10 1: "st" + %10 2: "nd" + %10 3: "rd" + %100 11 + %100 12 + %100 13 + %%: "th" diff --git a/locals/tr_TR.ruleset b/locals/tr_TR.ruleset new file mode 100644 index 0000000..df4d337 --- /dev/null +++ b/locals/tr_TR.ruleset @@ -0,0 +1,24 @@ +#magnitudes + now: "şimdi" + 1_second: "1 saniye" + seconds: "%d saniye" + 1_minute: "1 dakika" + minutes: "%d dakika" + 1_hour: "1 saat" + hours: "%d saat" + 1_day: "1 gün" + days: "%d gün" + 1_week: "1 hafta" + weeks: "%d hafta" + 1_month: "1 ay" + months: "%d ay" + 1_year: "1 yıl" + years: "%d yıl" + longtime: "uzun süre" + +#indicators + before: "önce" suffix + later: "sonra" suffix + +#ordinals + %%: "." diff --git a/ordinals.go b/ordinals.go index 43d88a8..912e59c 100644 --- a/ordinals.go +++ b/ordinals.go @@ -22,4 +22,5 @@ func Ordinal(x int) string { } } return strconv.Itoa(x) + suffix + } From ada225964facf99c16779304b47dd07610171f10 Mon Sep 17 00:00:00 2001 From: Dogacel Date: Sat, 16 Jun 2018 14:31:01 +0300 Subject: [PATCH 2/3] Implemented adding new language option. --- language.go | 73 +++++++++++++++++++++++++++++++++++++++++--- language_test.go | 13 ++++++++ locals/en_US.json | 40 ++++++++++++++++++++++++ locals/en_US.ruleset | 30 ------------------ locals/tr_TR.json | 36 ++++++++++++++++++++++ locals/tr_TR.ruleset | 24 --------------- ordinals.go | 58 ++++++++++++++++++++++++++++++++--- times.go | 51 +++++++++++++++++++------------ 8 files changed, 243 insertions(+), 82 deletions(-) create mode 100644 language_test.go create mode 100644 locals/en_US.json delete mode 100644 locals/en_US.ruleset create mode 100644 locals/tr_TR.json delete mode 100644 locals/tr_TR.ruleset diff --git a/language.go b/language.go index 94cb7a5..c445266 100644 --- a/language.go +++ b/language.go @@ -1,26 +1,89 @@ package humanize +import ( + "encoding/json" + "fmt" + "io/ioutil" +) + // Local type for the ordinals and times. type Local string +// Ruleset for accessing rules +type Ruleset struct { + Mags magnitudes `json:"magnitudes"` + Inds indicators `json:"indicators"` + Ords [][]string `json:"ordinals"` +} + +type magnitudes struct { + Now string + Second string + Minute string + Hour string + Day string + Week string + Month string + Year string + + Seconds string + Minutes string + Hours string + Days string + Weeks string + Months string + Years string + + Longtime string +} + +type indicator struct { + Word string + Fix string +} + +type indicators struct { + Before indicator + Later indicator +} + // Local for constant language values const ( - English Local = "en_US" - Turkish Local = "tr_TR" + English Local = "en_US" + Turkish Local = "tr_TR" + Uninitialized Local = "" ) -var active = English +var active = Uninitialized +var ruleset = Ruleset{} // GetLanguage of the humanizing option. func GetLanguage() Local { return active } +// GetRuleset returns current ruleset option +func GetRuleset() Ruleset { + return ruleset +} + // SetLanguage of the humanizing option. func SetLanguage(l Local) { active = l + parseRuleset(l) + UpdateMagnitudes() } -func ParseRuleset(l Local) { - +func parseRuleset(l Local) { + fmt.Println("Reading", "locals/"+string(l)+".json") + f, err := ioutil.ReadFile("locals/" + string(l) + ".json") + if err == nil { + ruleset = Ruleset{} + err := json.Unmarshal(f, &ruleset) + if err != nil { + fmt.Println(err) + } + } else { + fmt.Println("Error ! Can not read file.") + } } diff --git a/language_test.go b/language_test.go new file mode 100644 index 0000000..a8a8de1 --- /dev/null +++ b/language_test.go @@ -0,0 +1,13 @@ +package humanize + +import ( + "fmt" + "time" +) + +func EsxampleTurkish() { + SetLanguage(Turkish) + fmt.Println(Time(time.Now())) + SetLanguage(English) + // Output: şimdi +} diff --git a/locals/en_US.json b/locals/en_US.json new file mode 100644 index 0000000..a44003e --- /dev/null +++ b/locals/en_US.json @@ -0,0 +1,40 @@ +{ + "magnitudes": { + "now": "now", + "second": "1 second", + "seconds": "%d seconds", + "minute": "1 minute", + "minutes": "%d minutes", + "hour": "1 hour", + "hours": "%d hours", + "day": "1 day", + "days": "%d days", + "week": "1 week", + "weeks": "%d weeks", + "month": "1 month", + "months": "%d months", + "year": "1 year", + "years": "%d years", + "longtime": "a long while" + }, + + "indicators": { + "before": { + "word": "ago", + "fix": "suffix" + }, + + "later": { + "word": "from now", + "fix": "suffix" + } + }, + + "ordinals": [ + ["%.", "th"], + ["%10 1", "st"], + ["%10 2", "nd"], + ["%10 3", "rd"], + ["%100 11 %100 12 %100 13", "th"] + ] +} diff --git a/locals/en_US.ruleset b/locals/en_US.ruleset deleted file mode 100644 index 2dbe7fb..0000000 --- a/locals/en_US.ruleset +++ /dev/null @@ -1,30 +0,0 @@ -#magnitudes - now: "now" - 1_second: "1 second" - seconds: "%d seconds" - 1_minute: "1 minute" - minutes: "%d minutes" - 1_hour: "1 hour" - hours: "%d hours" - 1_day: "1 day" - days: "%d days" - 1_week: "1 week" - weeks: "%d weeks" - 1_month: "1 month" - months: "%d months" - 1_year: "1 year" - years: "%d years" - longtime: "a long while" - -#indicators - before: "ago" suffix - later: "from now" suffix - -#ordinals - %10 1: "st" - %10 2: "nd" - %10 3: "rd" - %100 11 - %100 12 - %100 13 - %%: "th" diff --git a/locals/tr_TR.json b/locals/tr_TR.json new file mode 100644 index 0000000..39b8772 --- /dev/null +++ b/locals/tr_TR.json @@ -0,0 +1,36 @@ +{ + "magnitudes": { + "now": "şimdi", + "second": "1 saniye", + "seconds": "%d saniye", + "minute": "1 dakika", + "minutes": "%d dakika", + "hour": "1 saat", + "hours": "%d saat", + "day": "1 gün", + "days": "%d gün", + "week": "1 hafta", + "weeks": "%d hafta", + "month": "1 ay", + "months": "%d ay", + "year": "1 yıl", + "years": "%d yıl", + "longtime": "uzun süre" + }, + + "indicators": { + "before": { + "word": "önce", + "fix": "suffix" + }, + + "later": { + "word": "sonra", + "fix": "suffix" + } + }, + + "ordinals": [ + ["%.", "."] + ] +} diff --git a/locals/tr_TR.ruleset b/locals/tr_TR.ruleset deleted file mode 100644 index df4d337..0000000 --- a/locals/tr_TR.ruleset +++ /dev/null @@ -1,24 +0,0 @@ -#magnitudes - now: "şimdi" - 1_second: "1 saniye" - seconds: "%d saniye" - 1_minute: "1 dakika" - minutes: "%d dakika" - 1_hour: "1 saat" - hours: "%d saat" - 1_day: "1 gün" - days: "%d gün" - 1_week: "1 hafta" - weeks: "%d hafta" - 1_month: "1 ay" - months: "%d ay" - 1_year: "1 yıl" - years: "%d yıl" - longtime: "uzun süre" - -#indicators - before: "önce" suffix - later: "sonra" suffix - -#ordinals - %%: "." diff --git a/ordinals.go b/ordinals.go index 912e59c..1cc9970 100644 --- a/ordinals.go +++ b/ordinals.go @@ -1,12 +1,62 @@ package humanize -import "strconv" +import ( + "strconv" + "strings" +) // Ordinal gives you the input number in a rank/ordinal format. // // Ordinal(3) -> 3rd -func Ordinal(x int) string { - suffix := "th" +func Ordinal(x int) (out string) { + if GetLanguage() == Uninitialized { + SetLanguage(English) + } + + ordinals := GetRuleset().Ords + + for _, rule := range ordinals { + out = applyRule(x, out, rule) + } + + out = strconv.Itoa(x) + out + + return out +} + +func applyRule(x int, in string, rule []string) (out string) { + subRules := strings.SplitAfter(rule[0], "%") + out = in + for _, s := range subRules { + if s == "%" { + continue + } + if s == "." { + out = rule[1] + } else { + if ruleMatches(x, s) { + out = rule[1] + } + } + } + + return out +} + +func ruleMatches(input int, rule string) bool { + r := strings.Split(rule, " ") + m1, _ := strconv.Atoi(r[0]) + m2, _ := strconv.Atoi(r[1]) + + if input%m1 == m2 { + return true + } + + return false +} + +/* +suffix := "th" switch x % 10 { case 1: if x%100 != 11 { @@ -23,4 +73,4 @@ func Ordinal(x int) string { } return strconv.Itoa(x) + suffix -} +*/ diff --git a/times.go b/times.go index dd3fbf5..8f64172 100644 --- a/times.go +++ b/times.go @@ -20,7 +20,15 @@ const ( // // Time(someT) -> "3 weeks ago" func Time(then time.Time) string { - return RelTime(then, time.Now(), "ago", "from now") + if GetLanguage() == Uninitialized { + SetLanguage(English) + } + return RelTime( + then, + time.Now(), + GetRuleset().Inds.Before.Word, + GetRuleset().Inds.Later.Word, + ) } // A RelTimeMagnitude struct contains a relative time point at which @@ -44,24 +52,29 @@ type RelTimeMagnitude struct { DivBy time.Duration } -var defaultMagnitudes = []RelTimeMagnitude{ - {time.Second, "now", time.Second}, - {2 * time.Second, "1 second %s", 1}, - {time.Minute, "%d seconds %s", time.Second}, - {2 * time.Minute, "1 minute %s", 1}, - {time.Hour, "%d minutes %s", time.Minute}, - {2 * time.Hour, "1 hour %s", 1}, - {Day, "%d hours %s", time.Hour}, - {2 * Day, "1 day %s", 1}, - {Week, "%d days %s", Day}, - {2 * Week, "1 week %s", 1}, - {Month, "%d weeks %s", Week}, - {2 * Month, "1 month %s", 1}, - {Year, "%d months %s", Month}, - {18 * Month, "1 year %s", 1}, - {2 * Year, "2 years %s", 1}, - {LongTime, "%d years %s", Year}, - {math.MaxInt64, "a long while %s", 1}, +var defaultMagnitudes = []RelTimeMagnitude{} + +// UpdateMagnitudes to current local ruleset +func UpdateMagnitudes() { + defaultMagnitudes = []RelTimeMagnitude{ + {time.Second, GetRuleset().Mags.Now, time.Second}, + {2 * time.Second, GetRuleset().Mags.Second + " %s", 1}, + {time.Minute, GetRuleset().Mags.Seconds + " %s", time.Second}, + {2 * time.Minute, GetRuleset().Mags.Minute + " %s", 1}, + {time.Hour, GetRuleset().Mags.Minutes + " %s", time.Minute}, + {2 * time.Hour, GetRuleset().Mags.Hour + " %s", 1}, + {Day, GetRuleset().Mags.Hours + " %s", time.Hour}, + {2 * Day, GetRuleset().Mags.Day + " %s", 1}, + {Week, GetRuleset().Mags.Days + " %s", Day}, + {2 * Week, GetRuleset().Mags.Week + " %s", 1}, + {Month, GetRuleset().Mags.Weeks + " %s", Week}, + {2 * Month, GetRuleset().Mags.Month + " %s", 1}, + {Year, GetRuleset().Mags.Months + " %s", Month}, + {18 * Month, GetRuleset().Mags.Year + " %s", 1}, + {2 * Year, "2" + GetRuleset().Mags.Years[2:] + " %s", 1}, + {LongTime, GetRuleset().Mags.Years + " %s", Year}, + {math.MaxInt64, GetRuleset().Mags.Longtime + " %s", 1}, + } } // RelTime formats a time into a relative string. From b50537d5ec2165a84ebb72150ff0543dfce5dd09 Mon Sep 17 00:00:00 2001 From: Dogacel Date: Sat, 16 Jun 2018 14:50:21 +0300 Subject: [PATCH 3/3] Added validate language function for not getting errors. --- language.go | 10 ++++++++++ ordinals.go | 4 +--- times.go | 4 +--- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/language.go b/language.go index c445266..e15cb5c 100644 --- a/language.go +++ b/language.go @@ -57,6 +57,16 @@ const ( var active = Uninitialized var ruleset = Ruleset{} +// ValidateLanguage for output +// Must be called before Time or Ordinal function +// If implemented to other functions, call it for not getting +// an error. This function automatically chooses language to English. +func ValidateLanguage() { + if active == Uninitialized { + SetLanguage(English) + } +} + // GetLanguage of the humanizing option. func GetLanguage() Local { return active diff --git a/ordinals.go b/ordinals.go index 1cc9970..0dcb6ad 100644 --- a/ordinals.go +++ b/ordinals.go @@ -9,9 +9,7 @@ import ( // // Ordinal(3) -> 3rd func Ordinal(x int) (out string) { - if GetLanguage() == Uninitialized { - SetLanguage(English) - } + ValidateLanguage() ordinals := GetRuleset().Ords diff --git a/times.go b/times.go index 8f64172..f5a1d0a 100644 --- a/times.go +++ b/times.go @@ -20,9 +20,7 @@ const ( // // Time(someT) -> "3 weeks ago" func Time(then time.Time) string { - if GetLanguage() == Uninitialized { - SetLanguage(English) - } + ValidateLanguage() return RelTime( then, time.Now(),