1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143
|
package main
import (
"encoding/xml"
"fmt"
"regexp"
"strings"
)
// SupplementalData is the top level struct of plural.xml
type SupplementalData struct {
XMLName xml.Name `xml:"supplementalData"`
PluralGroups []PluralGroup `xml:"plurals>pluralRules"`
}
// PluralGroup is a group of locales with the same plural rules.
type PluralGroup struct {
Locales string `xml:"locales,attr"`
PluralRules []PluralRule `xml:"pluralRule"`
}
// Name returns a unique name for this plural group.
func (pg *PluralGroup) Name() string {
n := strings.Title(pg.Locales)
return strings.Replace(n, " ", "", -1)
}
// SplitLocales returns all the locales in the PluralGroup as a slice.
func (pg *PluralGroup) SplitLocales() []string {
return strings.Split(pg.Locales, " ")
}
// PluralRule is the rule for a single plural form.
type PluralRule struct {
Count string `xml:"count,attr"`
Rule string `xml:",innerxml"`
}
// CountTitle returns the title case of the PluralRule's count.
func (pr *PluralRule) CountTitle() string {
return strings.Title(pr.Count)
}
// Condition returns the condition where the PluralRule applies.
func (pr *PluralRule) Condition() string {
i := strings.Index(pr.Rule, "@")
return pr.Rule[:i]
}
// Examples returns the integer and decimal exmaples for the PLuralRule.
func (pr *PluralRule) Examples() (integer []string, decimal []string) {
ex := strings.Replace(pr.Rule, ", …", "", -1)
ddelim := "@decimal"
if i := strings.Index(ex, ddelim); i > 0 {
dex := strings.TrimSpace(ex[i+len(ddelim):])
decimal = strings.Split(dex, ", ")
ex = ex[:i]
}
idelim := "@integer"
if i := strings.Index(ex, idelim); i > 0 {
iex := strings.TrimSpace(ex[i+len(idelim):])
integer = strings.Split(iex, ", ")
}
return integer, decimal
}
// IntegerExamples returns the integer exmaples for the PLuralRule.
func (pr *PluralRule) IntegerExamples() []string {
integer, _ := pr.Examples()
return integer
}
// DecimalExamples returns the decimal exmaples for the PLuralRule.
func (pr *PluralRule) DecimalExamples() []string {
_, decimal := pr.Examples()
return decimal
}
var relationRegexp = regexp.MustCompile(`([niftvw])(?:\s*%\s*([0-9]+))?\s*(!=|=)(.*)`)
// GoCondition converts the XML condition to valid Go code.
func (pr *PluralRule) GoCondition() string {
var ors []string
for _, and := range strings.Split(pr.Condition(), "or") {
var ands []string
for _, relation := range strings.Split(and, "and") {
parts := relationRegexp.FindStringSubmatch(relation)
if parts == nil {
continue
}
lvar, lmod, op, rhs := strings.Title(parts[1]), parts[2], parts[3], strings.TrimSpace(parts[4])
if op == "=" {
op = "=="
}
lvar = "ops." + lvar
var rhor []string
var rany []string
for _, rh := range strings.Split(rhs, ",") {
if parts := strings.Split(rh, ".."); len(parts) == 2 {
from, to := parts[0], parts[1]
if lvar == "ops.N" {
if lmod != "" {
rhor = append(rhor, fmt.Sprintf("ops.NModInRange(%s, %s, %s)", lmod, from, to))
} else {
rhor = append(rhor, fmt.Sprintf("ops.NInRange(%s, %s)", from, to))
}
} else if lmod != "" {
rhor = append(rhor, fmt.Sprintf("intInRange(%s %% %s, %s, %s)", lvar, lmod, from, to))
} else {
rhor = append(rhor, fmt.Sprintf("intInRange(%s, %s, %s)", lvar, from, to))
}
} else {
rany = append(rany, rh)
}
}
if len(rany) > 0 {
rh := strings.Join(rany, ",")
if lvar == "ops.N" {
if lmod != "" {
rhor = append(rhor, fmt.Sprintf("ops.NModEqualsAny(%s, %s)", lmod, rh))
} else {
rhor = append(rhor, fmt.Sprintf("ops.NEqualsAny(%s)", rh))
}
} else if lmod != "" {
rhor = append(rhor, fmt.Sprintf("intEqualsAny(%s %% %s, %s)", lvar, lmod, rh))
} else {
rhor = append(rhor, fmt.Sprintf("intEqualsAny(%s, %s)", lvar, rh))
}
}
r := strings.Join(rhor, " || ")
if len(rhor) > 1 {
r = "(" + r + ")"
}
if op == "!=" {
r = "!" + r
}
ands = append(ands, r)
}
ors = append(ors, strings.Join(ands, " && "))
}
return strings.Join(ors, " ||\n")
}
|