diff options
author | joeybloggs <Dean.Karn@gmail.com> | 2016-08-11 00:01:13 +0300 |
---|---|---|
committer | joeybloggs <Dean.Karn@gmail.com> | 2016-08-11 00:01:13 +0300 |
commit | f81dd14d3cd97e875a6241cf395dae384457c455 (patch) | |
tree | 3292e3570ac0b00e3e893517a6a5934dda471886 /cmd | |
parent | 0c695d8f7d7b0f0f955813f23d5814659e3d9bb2 (diff) |
add ordinal rules + some variable cleanup
Diffstat (limited to 'cmd')
-rw-r--r-- | cmd/generate_resources.go | 444 | ||||
-rw-r--r-- | cmd/translator.tmpl | 56 |
2 files changed, 457 insertions, 43 deletions
diff --git a/cmd/generate_resources.go b/cmd/generate_resources.go index f252a756..38182b8f 100644 --- a/cmd/generate_resources.go +++ b/cmd/generate_resources.go @@ -5,6 +5,7 @@ import ( "log" "os" "os/exec" + "regexp" "sort" "strings" @@ -36,19 +37,26 @@ var ( globCurrencyIdxMap = make(map[string]int) // ["USD"] = 0 globalCurrencies = make([]string, 0, 100) // array of currency codes index maps to enum tmpl *template.Template + nModRegex = regexp.MustCompile("(n%[0-9]+)") + iModRegex = regexp.MustCompile("(i%[0-9]+)") + wModRegex = regexp.MustCompile("(w%[0-9]+)") + fModRegex = regexp.MustCompile("(f%[0-9]+)") + tModRegex = regexp.MustCompile("(t%[0-9]+)") ) type translator struct { - Locale string - BaseLocale string - Plurals string - CardinalFunc string - Decimal string - Group string - Minus string - Percent string - PerMille string - Currencies string + Locale string + BaseLocale string + Plurals string + CardinalFunc string + PluralsOrdinal string + OrdinalFunc string + Decimal string + Group string + Minus string + Percent string + PerMille string + Currencies string } func main() { @@ -147,9 +155,12 @@ func postProcess(cldr *cldr.CLDR) { fmt.Println("Post Processing:", trans.Locale) - // plural rules + // cardinal plural rules trans.CardinalFunc, trans.Plurals = parseCardinalPluralRuleFunc(cldr, trans.BaseLocale) + //ordinal plural rules + trans.OrdinalFunc, trans.PluralsOrdinal = parseOrdinalPluralRuleFunc(cldr, trans.BaseLocale) + // ignore base locales if trans.BaseLocale == trans.Locale { found = false @@ -479,9 +490,9 @@ func (a ByRank) Less(i, j int) bool { return a[i].Rank < a[j].Rank } // TODO: cleanup function logic perhaps write a lexer... but it's working right now, and // I'm already farther down the rabbit hole than I'd like and so pulling the chute here. -func parseCardinalPluralRuleFunc(current *cldr.CLDR, baseLocale string) (results string, plurals string) { +func parseOrdinalPluralRuleFunc(current *cldr.CLDR, baseLocale string) (results string, plurals string) { - var prCardinal *struct { + var prOrdinal *struct { cldr.Common Locales string "xml:\"locales,attr\"" PluralRule []*struct { @@ -492,17 +503,297 @@ func parseCardinalPluralRuleFunc(current *cldr.CLDR, baseLocale string) (results var pluralArr []locales.PluralRule - for _, p := range current.Supplemental().Plurals { + // idx 0 is ordinal rules + for _, pr := range current.Supplemental().Plurals[0].PluralRules { + + locs := strings.Split(pr.Locales, " ") + + for _, loc := range locs { + + if loc == baseLocale { + + prOrdinal = pr + // for _, pl := range pr.PluralRule { + // fmt.Println(pl.Count, pl.Common.Data()) + // } + } + } + } + + // no plural rules for locale + if prOrdinal == nil { + plurals = "nil" + results = "return locales.PluralRuleUnknown" + return + } + + vals := make(map[string]struct{}) + first := true + + // pre parse for variables + for _, rule := range prOrdinal.PluralRule { + + ps1 := pluralStringToString(rule.Count) + psI := pluralStringToInt(rule.Count) + pluralArr = append(pluralArr, psI) + + data := strings.Replace(strings.Replace(strings.Replace(strings.TrimSpace(strings.SplitN(rule.Common.Data(), "@", 2)[0]), " = ", " == ", -1), " or ", " || ", -1), " and ", " && ", -1) + + if len(data) == 0 { + if len(prOrdinal.PluralRule) == 1 { + + results = "return locales." + ps1 + + } else { + + results += "\n\nreturn locales." + ps1 + // results += "else {\nreturn locales." + locales.PluralStringToString(rule.Count) + ", nil\n}" + } + + continue + } + + // // All need n, so always add + // if strings.Contains(data, "n") { + // vals[prVarFuncs["n"]] = struct{}{} + // } + + if strings.Contains(data, "i") { + vals[prVarFuncs["i"]] = struct{}{} + } + + // v is inherently avaialable as an argument + // if strings.Contains(data, "v") { + // vals[prVarFuncs["v"]] = struct{}{} + // } + + if strings.Contains(data, "w") { + vals[prVarFuncs["w"]] = struct{}{} + } + + if strings.Contains(data, "f") { + vals[prVarFuncs["f"]] = struct{}{} + } + + if strings.Contains(data, "t") { + vals[prVarFuncs["t"]] = struct{}{} + } + + if first { + results += "if " + first = false + } else { + results += "else if " + } + + stmt := "" + + // real work here + // + // split by 'or' then by 'and' allowing to better + // determine bracketing for formula + + ors := strings.Split(data, "||") + + for _, or := range ors { + + stmt += "(" + + ands := strings.Split(strings.TrimSpace(or), "&&") + + for _, and := range ands { + + inArg := false + pre := "" + lft := "" + preOperator := "" + args := strings.Split(strings.TrimSpace(and), " ") + + for _, a := range args { + + if inArg { + // check to see if is a value range 2..9 + + multiRange := strings.Count(a, "..") > 1 + cargs := strings.Split(strings.TrimSpace(a), ",") + hasBracket := len(cargs) > 1 + bracketAdded := false + lastWasRange := false + + for _, carg := range cargs { + + if rng := strings.Split(carg, ".."); len(rng) > 1 { + + if multiRange { + pre += " (" + } else { + pre += " " + } + + switch preOperator { + case "==": + pre += lft + " >= " + rng[0] + " && " + lft + "<=" + rng[1] + case "!=": + pre += lft + " < " + rng[0] + " && " + lft + " > " + rng[1] + } + + if multiRange { + pre += ") || " + } else { + pre += " || " + } - for _, pr := range p.PluralRules { + lastWasRange = true + continue + } - locs := strings.Split(pr.Locales, " ") + if lastWasRange { + pre = strings.TrimRight(pre, " || ") + " && " + } - for _, loc := range locs { + lastWasRange = false + + if hasBracket && !bracketAdded { + pre += "(" + bracketAdded = true + } - if loc == baseLocale { - prCardinal = pr + // single comma separated values + switch preOperator { + case "==": + pre += " " + lft + preOperator + carg + " || " + case "!=": + pre += " " + lft + preOperator + carg + " && " + } + + } + + pre = strings.TrimRight(pre, " || ") + pre = strings.TrimRight(pre, " && ") + pre = strings.TrimRight(pre, " || ") + + if hasBracket && bracketAdded { + pre += ")" + } + + continue + } + + if strings.Contains(a, "=") || a == ">" || a == "<" { + inArg = true + preOperator = a + continue + } + + lft += a } + + stmt += pre + " && " + } + + stmt = strings.TrimRight(stmt, " && ") + ") || " + } + + stmt = strings.TrimRight(stmt, " || ") + + results += stmt + + results += " {\n" + + // return plural rule here + results += "return locales." + ps1 + "\n" + + results += "}" + } + + pre := "\n" + + // always needed + vals[prVarFuncs["n"]] = struct{}{} + + sorted := make([]sortRank, 0, len(vals)) + + for k := range vals { + switch k[:1] { + case "n": + sorted = append(sorted, sortRank{ + Value: prVarFuncs["n"], + Rank: 1, + }) + case "i": + sorted = append(sorted, sortRank{ + Value: prVarFuncs["i"], + Rank: 2, + }) + case "w": + sorted = append(sorted, sortRank{ + Value: prVarFuncs["w"], + Rank: 3, + }) + case "f": + sorted = append(sorted, sortRank{ + Value: prVarFuncs["f"], + Rank: 4, + }) + case "t": + sorted = append(sorted, sortRank{ + Value: prVarFuncs["t"], + Rank: 5, + }) + } + } + + sort.Sort(ByRank(sorted)) + + for _, k := range sorted { + pre += k.Value + } + + if len(results) == 0 { + results = "return locales.PluralRuleUnknown" + } else { + + if !strings.HasPrefix(results, "return") { + + results = manyToSingleVars(results) + // pre += "\n" + results = pre + results + } + } + + if len(pluralArr) == 0 { + plurals = "nil" + } else { + plurals = fmt.Sprintf("%#v", pluralArr) + } + + return +} + +// TODO: cleanup function logic perhaps write a lexer... but it's working right now, and +// I'm already farther down the rabbit hole than I'd like and so pulling the chute here. +func parseCardinalPluralRuleFunc(current *cldr.CLDR, baseLocale string) (results string, plurals string) { + + var prCardinal *struct { + cldr.Common + Locales string "xml:\"locales,attr\"" + PluralRule []*struct { + cldr.Common + Count string "xml:\"count,attr\"" + } "xml:\"pluralRule\"" + } + + var pluralArr []locales.PluralRule + + // idx 2 is cardinal rules + for _, pr := range current.Supplemental().Plurals[2].PluralRules { + + locs := strings.Split(pr.Locales, " ") + + for _, loc := range locs { + + if loc == baseLocale { + prCardinal = pr } } } @@ -736,13 +1027,14 @@ func parseCardinalPluralRuleFunc(current *cldr.CLDR, baseLocale string) (results pre += k.Value } - pre += "\n" - if len(results) == 0 { results = "return locales.PluralRuleUnknown" } else { if !strings.HasPrefix(results, "return") { + + results = manyToSingleVars(results) + // pre += "\n" results = pre + results } } @@ -756,6 +1048,116 @@ func parseCardinalPluralRuleFunc(current *cldr.CLDR, baseLocale string) (results return } +func manyToSingleVars(input string) (results string) { + + matches := nModRegex.FindAllString(input, -1) + mp := make(map[string][]string) // map of formula to variable + var found bool + var split []string + var variable string + + for _, formula := range matches { + + if _, found = mp[formula]; found { + continue + } + + split = strings.SplitN(formula, "%", 2) + + mp[formula] = []string{split[1], "math.Mod(" + split[0] + ", " + split[1] + ")"} + } + + for k, v := range mp { + variable = "nMod" + v[0] + results += variable + " := " + v[1] + "\n" + input = strings.Replace(input, k, variable, -1) + } + + matches = iModRegex.FindAllString(input, -1) + mp = make(map[string][]string) // map of formula to variable + + for _, formula := range matches { + + if _, found = mp[formula]; found { + continue + } + + split = strings.SplitN(formula, "%", 2) + + mp[formula] = []string{split[1], formula} + } + + for k, v := range mp { + variable = "iMod" + v[0] + results += variable + " := " + v[1] + "\n" + input = strings.Replace(input, k, variable, -1) + } + + matches = wModRegex.FindAllString(input, -1) + mp = make(map[string][]string) // map of formula to variable + + for _, formula := range matches { + + if _, found = mp[formula]; found { + continue + } + + split = strings.SplitN(formula, "%", 2) + + mp[formula] = []string{split[1], formula} + } + + for k, v := range mp { + variable = "wMod" + v[0] + results += variable + " := " + v[1] + "\n" + input = strings.Replace(input, k, variable, -1) + } + + matches = fModRegex.FindAllString(input, -1) + mp = make(map[string][]string) // map of formula to variable + + for _, formula := range matches { + + if _, found = mp[formula]; found { + continue + } + + split = strings.SplitN(formula, "%", 2) + + mp[formula] = []string{split[1], formula} + } + + for k, v := range mp { + variable = "fMod" + v[0] + results += variable + " := " + v[1] + "\n" + input = strings.Replace(input, k, variable, -1) + } + + matches = tModRegex.FindAllString(input, -1) + mp = make(map[string][]string) // map of formula to variable + + for _, formula := range matches { + + if _, found = mp[formula]; found { + continue + } + + split = strings.SplitN(formula, "%", 2) + + mp[formula] = []string{split[1], formula} + } + + for k, v := range mp { + variable = "tMod" + v[0] + results += variable + " := " + v[1] + "\n" + input = strings.Replace(input, k, variable, -1) + } + + results = results + "\n" + input + + return +} + // pluralStringToInt returns the enum value of 'plural' provided func pluralStringToInt(plural string) locales.PluralRule { diff --git a/cmd/translator.tmpl b/cmd/translator.tmpl index bfef339a..15729144 100644 --- a/cmd/translator.tmpl +++ b/cmd/translator.tmpl @@ -8,43 +8,55 @@ import ( ) type {{ .Locale }} struct { - locale string - plurals []locales.PluralRule - decimal []byte - group []byte - minus []byte - percent []byte - perMille []byte - currencies [][]byte // idx = enum of currency code + locale string + pluralsCardinal []locales.PluralRule + pluralsOrdinal []locales.PluralRule + decimal []byte + group []byte + minus []byte + percent []byte + perMille []byte + currencies [][]byte // idx = enum of currency code } // New returns a new instance of translator for the '{{ .Locale }}' locale func New() locales.Translator { return &{{ .Locale }}{ - locale: "{{ .Locale }}", - plurals: {{ .Plurals }}, - decimal: {{ .Decimal }}, - group: {{ .Group }}, - minus: {{ .Minus }}, - percent: {{ .Percent }}, - perMille: {{ .PerMille }}, - currencies: {{ .Currencies }}, + locale: "{{ .Locale }}", + pluralsCardinal: {{ .Plurals }}, + pluralsOrdinal: {{ .PluralsOrdinal }}, + decimal: {{ .Decimal }}, + group: {{ .Group }}, + minus: {{ .Minus }}, + percent: {{ .Percent }}, + perMille: {{ .PerMille }}, + currencies: {{ .Currencies }}, } } // Locale returns the current translators string locale -func(t *{{ .Locale }}) Locale() string { - return t.locale +func({{ .BaseLocale }} *{{ .Locale }}) Locale() string { + return {{ .BaseLocale }}.locale } // PluralsCardinal returns the list of cardinal plural rules associated with '{{ .Locale }}' -func(t *{{ .Locale }}) PluralsCardinal() []locales.PluralRule { - return t.plurals +func({{ .BaseLocale }} *{{ .Locale }}) PluralsCardinal() []locales.PluralRule { + return {{ .BaseLocale }}.pluralsCardinal } -// cardinalPluralRule returns the PluralRule given 'num' and digits/precision of 'v' for '{{ .Locale }}' -func(t *{{ .Locale }}) cardinalPluralRule(num float64, v uint64) locales.PluralRule { +// PluralsOrdinal returns the list of ordinal plural rules associated with '{{ .Locale }}' +func({{ .BaseLocale }} *{{ .Locale }}) PluralsOrdinal() []locales.PluralRule { + return {{ .BaseLocale }}.pluralsOrdinal +} + +// cardinalPluralRule returns the cardinal PluralRule given 'num' and digits/precision of 'v' for '{{ .Locale }}' +func({{ .BaseLocale }} *{{ .Locale }}) cardinalPluralRule(num float64, v uint64) locales.PluralRule { {{ .CardinalFunc }} } +// ordinalPluralRule returns the ordinal PluralRule given 'num' and digits/precision of 'v' for '{{ .Locale }}' +func({{ .BaseLocale }} *{{ .Locale }}) ordinalPluralRule(num float64, v uint64) locales.PluralRule { + {{ .OrdinalFunc }} +} + {{ end }}
\ No newline at end of file |