generate_resources.go 68 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622262326242625262626272628262926302631263226332634263526362637263826392640264126422643264426452646264726482649265026512652265326542655265626572658265926602661266226632664266526662667266826692670267126722673267426752676267726782679268026812682268326842685268626872688268926902691269226932694269526962697269826992700270127022703270427052706270727082709271027112712271327142715271627172718271927202721272227232724272527262727272827292730273127322733273427352736273727382739274027412742274327442745274627472748274927502751275227532754275527562757275827592760276127622763276427652766276727682769277027712772277327742775277627772778277927802781278227832784278527862787278827892790279127922793279427952796279727982799280028012802280328042805280628072808280928102811281228132814281528162817281828192820282128222823282428252826282728282829283028312832283328342835283628372838283928402841284228432844284528462847284828492850285128522853285428552856285728582859286028612862286328642865286628672868286928702871287228732874287528762877287828792880288128822883288428852886288728882889289028912892289328942895
  1. package main
  2. import (
  3. "fmt"
  4. "log"
  5. "os"
  6. "os/exec"
  7. "regexp"
  8. "sort"
  9. "strconv"
  10. "strings"
  11. "github.com/go-playground/locales"
  12. "golang.org/x/text/unicode/cldr"
  13. "text/template"
  14. )
  15. const (
  16. locDir = "../%s"
  17. locFilename = locDir + "/%s.go"
  18. )
  19. var (
  20. tfuncs = template.FuncMap{
  21. "is_multibyte": func(s string) bool {
  22. return len([]byte(s)) > 1
  23. },
  24. "reverse_bytes": func(s string) string {
  25. b := make([]byte, 0, 8)
  26. for j := len(s) - 1; j >= 0; j-- {
  27. b = append(b, s[j])
  28. }
  29. return fmt.Sprintf("%#v", b)
  30. },
  31. "byte_count": func(s ...string) string {
  32. var count int
  33. for i := 0; i < len(s); i++ {
  34. count += len([]byte(s[i]))
  35. }
  36. return strconv.Itoa(count)
  37. },
  38. }
  39. prVarFuncs = map[string]string{
  40. "n": "n := math.Abs(num)\n",
  41. "i": "i := int64(n)\n",
  42. // "v": "v := ...", // inherently available as argument
  43. "w": "w := locales.W(n, v)\n",
  44. "f": "f := locales.F(n, v)\n",
  45. "t": "t := locales.T(n, v)\n",
  46. }
  47. translators = make(map[string]*translator)
  48. baseTranslators = make(map[string]*translator)
  49. globalCurrenciesMap = make(map[string]struct{}) // ["USD"] = "$" currency code, just all currencies for mapping to enum
  50. globCurrencyIdxMap = make(map[string]int) // ["USD"] = 0
  51. globalCurrencies = make([]string, 0, 100) // array of currency codes index maps to enum
  52. tmpl *template.Template
  53. nModRegex = regexp.MustCompile("(n%[0-9]+)")
  54. iModRegex = regexp.MustCompile("(i%[0-9]+)")
  55. wModRegex = regexp.MustCompile("(w%[0-9]+)")
  56. fModRegex = regexp.MustCompile("(f%[0-9]+)")
  57. tModRegex = regexp.MustCompile("(t%[0-9]+)")
  58. groupLenRegex = regexp.MustCompile(",([0-9#]+)\\.")
  59. groupLenPercentRegex = regexp.MustCompile(",([0-9#]+)$")
  60. secondaryGroupLenRegex = regexp.MustCompile(",([0-9#]+),")
  61. requiredNumRegex = regexp.MustCompile("([0-9]+)\\.")
  62. requiredDecimalRegex = regexp.MustCompile("\\.([0-9]+)")
  63. enInheritance = map[string]string{
  64. "en_150": "en_001", "en_AG": "en_001", "en_AI": "en_001", "en_AU": "en_001", "en_BB": "en_001", "en_BE": "en_001", "en_BM": "en_001", "en_BS": "en_001", "en_BW": "en_001", "en_BZ": "en_001", "en_CA": "en_001", "en_CC": "en_001", "en_CK": "en_001", "en_CM": "en_001", "en_CX": "en_001", "en_CY": "en_001", "en_DG": "en_001", "en_DM": "en_001", "en_ER": "en_001", "en_FJ": "en_001", "en_FK": "en_001", "en_FM": "en_001", "en_GB": "en_001", "en_GD": "en_001", "en_GG": "en_001", "en_GH": "en_001", "en_GI": "en_001", "en_GM": "en_001", "en_GY": "en_001", "en_HK": "en_001", "en_IE": "en_001", "en_IL": "en_001", "en_IM": "en_001", "en_IN": "en_001", "en_IO": "en_001", "en_JE": "en_001", "en_JM": "en_001", "en_KE": "en_001", "en_KI": "en_001", "en_KN": "en_001", "en_KY": "en_001", "en_LC": "en_001", "en_LR": "en_001", "en_LS": "en_001", "en_MG": "en_001", "en_MO": "en_001", "en_MS": "en_001", "en_MT": "en_001", "en_MU": "en_001", "en_MW": "en_001", "en_MY": "en_001", "en_NA": "en_001", "en_NF": "en_001", "en_NG": "en_001", "en_NR": "en_001", "en_NU": "en_001", "en_NZ": "en_001", "en_PG": "en_001", "en_PH": "en_001", "en_PK": "en_001", "en_PN": "en_001", "en_PW": "en_001", "en_RW": "en_001", "en_SB": "en_001", "en_SC": "en_001", "en_SD": "en_001", "en_SG": "en_001", "en_SH": "en_001", "en_SL": "en_001", "en_SS": "en_001", "en_SX": "en_001", "en_SZ": "en_001", "en_TC": "en_001", "en_TK": "en_001", "en_TO": "en_001", "en_TT": "en_001", "en_TV": "en_001", "en_TZ": "en_001", "en_UG": "en_001", "en_VC": "en_001", "en_VG": "en_001", "en_VU": "en_001", "en_WS": "en_001", "en_ZA": "en_001", "en_ZM": "en_001", "en_ZW": "en_001", }
  65. en150Inheritance = map[string]string{"en_AT": "en_150", "en_CH": "en_150", "en_DE": "en_150", "en_DK": "en_150", "en_FI": "en_150", "en_NL": "en_150", "en_SE": "en_150", "en_SI": "en_150"}
  66. es419Inheritance = map[string]string{
  67. "es_AR": "es_419", "es_BO": "es_419", "es_BR": "es_419", "es_BZ": "es_419", "es_CL": "es_419", "es_CO": "es_419", "es_CR": "es_419", "es_CU": "es_419", "es_DO": "es_419", "es_EC": "es_419", "es_GT": "es_419", "es_HN": "es_419", "es_MX": "es_419", "es_NI": "es_419", "es_PA": "es_419", "es_PE": "es_419", "es_PR": "es_419", "es_PY": "es_419", "es_SV": "es_419", "es_US": "es_419", "es_UY": "es_419", "es_VE": "es_419",
  68. }
  69. rootInheritance = map[string]string{
  70. "az_Arab": "root", "az_Cyrl": "root", "bm_Nkoo": "root", "bs_Cyrl": "root", "en_Dsrt": "root", "en_Shaw": "root", "ha_Arab": "root", "iu_Latn": "root", "mn_Mong": "root", "ms_Arab": "root", "pa_Arab": "root", "shi_Latn": "root", "sr_Latn": "root", "uz_Arab": "root", "uz_Cyrl": "root", "vai_Latn": "root", "zh_Hant": "root", "yue_Hans": "root",
  71. }
  72. ptPtInheritance = map[string]string{
  73. "pt_AO": "pt_PT", "pt_CH": "pt_PT", "pt_CV": "pt_PT", "pt_GQ": "pt_PT", "pt_GW": "pt_PT", "pt_LU": "pt_PT", "pt_MO": "pt_PT", "pt_MZ": "pt_PT", "pt_ST": "pt_PT", "pt_TL": "pt_PT",
  74. }
  75. zhHantHKInheritance = map[string]string{
  76. "zh_Hant_MO": "zh_Hant_HK",
  77. }
  78. inheritMaps = []map[string]string{ enInheritance, en150Inheritance, es419Inheritance, rootInheritance, ptPtInheritance, zhHantHKInheritance}
  79. )
  80. type translator struct {
  81. Locale string
  82. BaseLocale string
  83. // InheritedLocale string
  84. Plurals string
  85. CardinalFunc string
  86. PluralsOrdinal string
  87. OrdinalFunc string
  88. PluralsRange string
  89. RangeFunc string
  90. Decimal string
  91. Group string
  92. Minus string
  93. Percent string
  94. PerMille string
  95. TimeSeparator string
  96. Infinity string
  97. Currencies string
  98. // FmtNumber vars
  99. FmtNumberExists bool
  100. FmtNumberGroupLen int
  101. FmtNumberSecondaryGroupLen int
  102. FmtNumberMinDecimalLen int
  103. // FmtPercent vars
  104. FmtPercentExists bool
  105. FmtPercentGroupLen int
  106. FmtPercentSecondaryGroupLen int
  107. FmtPercentMinDecimalLen int
  108. FmtPercentPrefix string
  109. FmtPercentSuffix string
  110. FmtPercentInPrefix bool
  111. FmtPercentLeft bool
  112. // FmtCurrency vars
  113. FmtCurrencyExists bool
  114. FmtCurrencyGroupLen int
  115. FmtCurrencySecondaryGroupLen int
  116. FmtCurrencyMinDecimalLen int
  117. FmtCurrencyPrefix string
  118. FmtCurrencySuffix string
  119. FmtCurrencyInPrefix bool
  120. FmtCurrencyLeft bool
  121. FmtCurrencyNegativeExists bool
  122. FmtCurrencyNegativePrefix string
  123. FmtCurrencyNegativeSuffix string
  124. FmtCurrencyNegativeInPrefix bool
  125. FmtCurrencyNegativeLeft bool
  126. // Date & Time
  127. FmtCalendarExists bool
  128. FmtMonthsAbbreviated string
  129. FmtMonthsNarrow string
  130. FmtMonthsWide string
  131. FmtDaysAbbreviated string
  132. FmtDaysNarrow string
  133. FmtDaysShort string
  134. FmtDaysWide string
  135. FmtPeriodsAbbreviated string
  136. FmtPeriodsNarrow string
  137. FmtPeriodsShort string
  138. FmtPeriodsWide string
  139. FmtErasAbbreviated string
  140. FmtErasNarrow string
  141. FmtErasWide string
  142. FmtTimezones string
  143. // calculation only fields below this point...
  144. DecimalNumberFormat string
  145. PercentNumberFormat string
  146. CurrencyNumberFormat string
  147. NegativeCurrencyNumberFormat string
  148. // Dates
  149. FmtDateFull string
  150. FmtDateLong string
  151. FmtDateMedium string
  152. FmtDateShort string
  153. // Times
  154. FmtTimeFull string
  155. FmtTimeLong string
  156. FmtTimeMedium string
  157. FmtTimeShort string
  158. // timezones per locale by type
  159. timezones map[string]*zoneAbbrev // key = type eg. America_Eastern zone Abbrev will be long form eg. Eastern Standard Time, Pacific Standard Time.....
  160. }
  161. type zoneAbbrev struct {
  162. standard string
  163. daylight string
  164. }
  165. var timezones = map[string]*zoneAbbrev{} // key = type eg. America_Eastern zone Abbrev eg. EST & EDT
  166. func main() {
  167. var err error
  168. // load template
  169. tmpl, err = template.New("all").Funcs(tfuncs).ParseGlob("*.tmpl")
  170. if err != nil {
  171. log.Fatal(err)
  172. }
  173. // load CLDR recourses
  174. var decoder cldr.Decoder
  175. cldr, err := decoder.DecodePath("data/core")
  176. if err != nil {
  177. panic("failed decode CLDR data; " + err.Error())
  178. }
  179. preProcess(cldr)
  180. postProcess(cldr)
  181. var currencies string
  182. for i, curr := range globalCurrencies {
  183. if i == 0 {
  184. currencies = curr + " Type = iota\n"
  185. continue
  186. }
  187. currencies += curr + "\n"
  188. }
  189. if err = os.MkdirAll(fmt.Sprintf(locDir, "currency"), 0777); err != nil {
  190. log.Fatal(err)
  191. }
  192. filename := fmt.Sprintf(locFilename, "currency", "currency")
  193. output, err := os.Create(filename)
  194. if err != nil {
  195. log.Fatal(err)
  196. }
  197. defer output.Close()
  198. if err := tmpl.ExecuteTemplate(output, "currencies", currencies); err != nil {
  199. log.Fatal(err)
  200. }
  201. output.Close()
  202. // after file written run gofmt on file to ensure best formatting
  203. cmd := exec.Command("goimports", "-w", filename)
  204. if err = cmd.Run(); err != nil {
  205. log.Panic("failed execute \"goimports\" for file ", filename, ": ", err)
  206. }
  207. cmd = exec.Command("gofmt", "-s", "-w", filename)
  208. if err = cmd.Run(); err != nil {
  209. log.Panic("failed execute \"gofmt\" for file ", filename, ": ", err)
  210. }
  211. for _, trans := range translators {
  212. fmt.Println("Writing Data:", trans.Locale)
  213. if err = os.MkdirAll(fmt.Sprintf(locDir, trans.Locale), 0777); err != nil {
  214. log.Fatal(err)
  215. }
  216. filename = fmt.Sprintf(locFilename, trans.Locale, trans.Locale)
  217. output, err := os.Create(filename)
  218. if err != nil {
  219. log.Fatal(err)
  220. }
  221. defer output.Close()
  222. if err := tmpl.ExecuteTemplate(output, "translator", trans); err != nil {
  223. log.Fatal(err)
  224. }
  225. output.Close()
  226. // after file written run gofmt on file to ensure best formatting
  227. cmd := exec.Command("goimports", "-w", filename)
  228. if err = cmd.Run(); err != nil {
  229. log.Panic("failed execute \"goimports\" for file ", filename, ": ", err)
  230. }
  231. // this simplifies some syntax that I can;t find an option for in goimports, namely '-s'
  232. cmd = exec.Command("gofmt", "-s", "-w", filename)
  233. if err = cmd.Run(); err != nil {
  234. log.Panic("failed execute \"gofmt\" for file ", filename, ": ", err)
  235. }
  236. filename = fmt.Sprintf(locFilename, trans.Locale, trans.Locale+"_test")
  237. if _, err := os.Stat(filename); err == nil {
  238. fmt.Println("*************** test file exists, skipping:", filename)
  239. continue
  240. }
  241. output, err = os.Create(filename)
  242. if err != nil {
  243. log.Fatal(err)
  244. }
  245. defer output.Close()
  246. if err := tmpl.ExecuteTemplate(output, "tests", trans); err != nil {
  247. log.Fatal(err)
  248. }
  249. output.Close()
  250. // after file written run gofmt on file to ensure best formatting
  251. cmd = exec.Command("goimports", "-w", filename)
  252. if err = cmd.Run(); err != nil {
  253. log.Panic("failed execute \"goimports\" for file ", filename, ": ", err)
  254. }
  255. // this simplifies some syntax that I can;t find an option for in goimports, namely '-s'
  256. cmd = exec.Command("gofmt", "-s", "-w", filename)
  257. if err = cmd.Run(); err != nil {
  258. log.Panic("failed execute \"gofmt\" for file ", filename, ": ", err)
  259. }
  260. }
  261. }
  262. func applyOverrides(trans *translator) {
  263. if trans.BaseLocale == "ru" {
  264. trans.PercentNumberFormat = "#,##0%"
  265. }
  266. }
  267. func postProcess(cldr *cldr.CLDR) {
  268. for _, v := range timezones {
  269. // no DST
  270. if len(v.daylight) == 0 {
  271. v.daylight = v.standard
  272. }
  273. }
  274. var inherited *translator
  275. var base *translator
  276. var inheritedFound, baseFound bool
  277. for _, trans := range translators {
  278. fmt.Println("Post Processing:", trans.Locale)
  279. // cardinal plural rules
  280. trans.CardinalFunc, trans.Plurals = parseCardinalPluralRuleFunc(cldr, trans.Locale, trans.BaseLocale)
  281. //ordinal plural rules
  282. trans.OrdinalFunc, trans.PluralsOrdinal = parseOrdinalPluralRuleFunc(cldr, trans.BaseLocale)
  283. // range plural rules
  284. trans.RangeFunc, trans.PluralsRange = parseRangePluralRuleFunc(cldr, trans.BaseLocale)
  285. // ignore base locales
  286. if trans.BaseLocale == trans.Locale {
  287. inheritedFound = false
  288. baseFound = false
  289. } else {
  290. inheritedFound = false
  291. for _, inheritMap := range(inheritMaps) {
  292. if inherit, found := inheritMap[trans.Locale]; found {
  293. inherited, inheritedFound = translators[inherit]
  294. break;
  295. }
  296. }
  297. base, baseFound = baseTranslators[trans.BaseLocale]
  298. }
  299. // Numbers
  300. if len(trans.Decimal) == 0 {
  301. if inheritedFound {
  302. trans.Decimal = inherited.Decimal
  303. }
  304. if len(trans.Decimal) == 0 && baseFound {
  305. trans.Decimal = base.Decimal
  306. }
  307. if len(trans.Decimal) == 0 {
  308. trans.Decimal = ""
  309. }
  310. }
  311. if len(trans.Group) == 0 {
  312. if inheritedFound {
  313. trans.Group = inherited.Group
  314. }
  315. if len(trans.Group) == 0 && baseFound {
  316. trans.Group = base.Group
  317. }
  318. if len(trans.Group) == 0 {
  319. trans.Group = ""
  320. }
  321. }
  322. if len(trans.Minus) == 0 {
  323. if inheritedFound {
  324. trans.Minus = inherited.Minus
  325. }
  326. if len(trans.Minus) == 0 && baseFound {
  327. trans.Minus = base.Minus
  328. }
  329. if len(trans.Minus) == 0 {
  330. trans.Minus = ""
  331. }
  332. }
  333. if len(trans.Percent) == 0 {
  334. if inheritedFound {
  335. trans.Percent = inherited.Percent
  336. }
  337. if len(trans.Percent) == 0 && baseFound {
  338. trans.Percent = base.Percent
  339. }
  340. if len(trans.Percent) == 0 {
  341. trans.Percent = ""
  342. }
  343. }
  344. if len(trans.PerMille) == 0 {
  345. if inheritedFound {
  346. trans.PerMille = inherited.PerMille
  347. }
  348. if len(trans.PerMille) == 0 && baseFound {
  349. trans.PerMille = base.PerMille
  350. }
  351. if len(trans.PerMille) == 0 {
  352. trans.PerMille = ""
  353. }
  354. }
  355. if len(trans.TimeSeparator) == 0 && inheritedFound {
  356. trans.TimeSeparator = inherited.TimeSeparator
  357. }
  358. if len(trans.TimeSeparator) == 0 && baseFound {
  359. trans.TimeSeparator = base.TimeSeparator
  360. }
  361. if len(trans.Infinity) == 0 && inheritedFound {
  362. trans.Infinity = inherited.Infinity
  363. }
  364. if len(trans.Infinity) == 0 && baseFound {
  365. trans.Infinity = base.Infinity
  366. }
  367. // Currency
  368. // number values
  369. if len(trans.DecimalNumberFormat) == 0 && inheritedFound {
  370. trans.DecimalNumberFormat = inherited.DecimalNumberFormat
  371. }
  372. if len(trans.DecimalNumberFormat) == 0 && baseFound {
  373. trans.DecimalNumberFormat = base.DecimalNumberFormat
  374. }
  375. if len(trans.PercentNumberFormat) == 0 && inheritedFound {
  376. trans.PercentNumberFormat = inherited.PercentNumberFormat
  377. }
  378. if len(trans.PercentNumberFormat) == 0 && baseFound {
  379. trans.PercentNumberFormat = base.PercentNumberFormat
  380. }
  381. if len(trans.CurrencyNumberFormat) == 0 && inheritedFound {
  382. trans.CurrencyNumberFormat = inherited.CurrencyNumberFormat
  383. }
  384. if len(trans.CurrencyNumberFormat) == 0 && baseFound {
  385. trans.CurrencyNumberFormat = base.CurrencyNumberFormat
  386. }
  387. if len(trans.NegativeCurrencyNumberFormat) == 0 && inheritedFound {
  388. trans.NegativeCurrencyNumberFormat = inherited.NegativeCurrencyNumberFormat
  389. }
  390. if len(trans.NegativeCurrencyNumberFormat) == 0 && baseFound {
  391. trans.NegativeCurrencyNumberFormat = base.NegativeCurrencyNumberFormat
  392. }
  393. // date values
  394. if len(trans.FmtDateFull) == 0 && inheritedFound {
  395. trans.FmtDateFull = inherited.FmtDateFull
  396. }
  397. if len(trans.FmtDateFull) == 0 && baseFound {
  398. trans.FmtDateFull = base.FmtDateFull
  399. }
  400. if len(trans.FmtDateLong) == 0 && inheritedFound {
  401. trans.FmtDateLong = inherited.FmtDateLong
  402. }
  403. if len(trans.FmtDateLong) == 0 && baseFound {
  404. trans.FmtDateLong = base.FmtDateLong
  405. }
  406. if len(trans.FmtDateMedium) == 0 && inheritedFound {
  407. trans.FmtDateMedium = inherited.FmtDateMedium
  408. }
  409. if len(trans.FmtDateMedium) == 0 && baseFound {
  410. trans.FmtDateMedium = base.FmtDateMedium
  411. }
  412. if len(trans.FmtDateShort) == 0 && inheritedFound {
  413. trans.FmtDateShort = inherited.FmtDateShort
  414. }
  415. if len(trans.FmtDateShort) == 0 && baseFound {
  416. trans.FmtDateShort = base.FmtDateShort
  417. }
  418. // time values
  419. if len(trans.FmtTimeFull) == 0 && inheritedFound {
  420. trans.FmtTimeFull = inherited.FmtTimeFull
  421. }
  422. if len(trans.FmtTimeFull) == 0 && baseFound {
  423. trans.FmtTimeFull = base.FmtTimeFull
  424. }
  425. if len(trans.FmtTimeLong) == 0 && inheritedFound {
  426. trans.FmtTimeLong = inherited.FmtTimeLong
  427. }
  428. if len(trans.FmtTimeLong) == 0 && baseFound {
  429. trans.FmtTimeLong = base.FmtTimeLong
  430. }
  431. if len(trans.FmtTimeMedium) == 0 && inheritedFound {
  432. trans.FmtTimeMedium = inherited.FmtTimeMedium
  433. }
  434. if len(trans.FmtTimeMedium) == 0 && baseFound {
  435. trans.FmtTimeMedium = base.FmtTimeMedium
  436. }
  437. if len(trans.FmtTimeShort) == 0 && inheritedFound {
  438. trans.FmtTimeShort = inherited.FmtTimeShort
  439. }
  440. if len(trans.FmtTimeShort) == 0 && baseFound {
  441. trans.FmtTimeShort = base.FmtTimeShort
  442. }
  443. // month values
  444. if len(trans.FmtMonthsAbbreviated) == 0 && inheritedFound {
  445. trans.FmtMonthsAbbreviated = inherited.FmtMonthsAbbreviated
  446. }
  447. if len(trans.FmtMonthsAbbreviated) == 0 && baseFound {
  448. trans.FmtMonthsAbbreviated = base.FmtMonthsAbbreviated
  449. }
  450. if len(trans.FmtMonthsNarrow) == 0 && inheritedFound {
  451. trans.FmtMonthsNarrow = inherited.FmtMonthsNarrow
  452. }
  453. if len(trans.FmtMonthsNarrow) == 0 && baseFound {
  454. trans.FmtMonthsNarrow = base.FmtMonthsNarrow
  455. }
  456. if len(trans.FmtMonthsWide) == 0 && inheritedFound {
  457. trans.FmtMonthsWide = inherited.FmtMonthsWide
  458. }
  459. if len(trans.FmtMonthsWide) == 0 && baseFound {
  460. trans.FmtMonthsWide = base.FmtMonthsWide
  461. }
  462. // day values
  463. if len(trans.FmtDaysAbbreviated) == 0 && inheritedFound {
  464. trans.FmtDaysAbbreviated = inherited.FmtDaysAbbreviated
  465. }
  466. if len(trans.FmtDaysAbbreviated) == 0 && baseFound {
  467. trans.FmtDaysAbbreviated = base.FmtDaysAbbreviated
  468. }
  469. if len(trans.FmtDaysNarrow) == 0 && inheritedFound {
  470. trans.FmtDaysNarrow = inherited.FmtDaysNarrow
  471. }
  472. if len(trans.FmtDaysNarrow) == 0 && baseFound {
  473. trans.FmtDaysNarrow = base.FmtDaysNarrow
  474. }
  475. if len(trans.FmtDaysShort) == 0 && inheritedFound {
  476. trans.FmtDaysShort = inherited.FmtDaysShort
  477. }
  478. if len(trans.FmtDaysShort) == 0 && baseFound {
  479. trans.FmtDaysShort = base.FmtDaysShort
  480. }
  481. if len(trans.FmtDaysWide) == 0 && inheritedFound {
  482. trans.FmtDaysWide = inherited.FmtDaysWide
  483. }
  484. if len(trans.FmtDaysWide) == 0 && baseFound {
  485. trans.FmtDaysWide = base.FmtDaysWide
  486. }
  487. // period values
  488. if len(trans.FmtPeriodsAbbreviated) == 0 && inheritedFound {
  489. trans.FmtPeriodsAbbreviated = inherited.FmtPeriodsAbbreviated
  490. }
  491. if len(trans.FmtPeriodsAbbreviated) == 0 && baseFound {
  492. trans.FmtPeriodsAbbreviated = base.FmtPeriodsAbbreviated
  493. }
  494. if len(trans.FmtPeriodsNarrow) == 0 && inheritedFound {
  495. trans.FmtPeriodsNarrow = inherited.FmtPeriodsNarrow
  496. }
  497. if len(trans.FmtPeriodsNarrow) == 0 && baseFound {
  498. trans.FmtPeriodsNarrow = base.FmtPeriodsNarrow
  499. }
  500. if len(trans.FmtPeriodsShort) == 0 && inheritedFound {
  501. trans.FmtPeriodsShort = inherited.FmtPeriodsShort
  502. }
  503. if len(trans.FmtPeriodsShort) == 0 && baseFound {
  504. trans.FmtPeriodsShort = base.FmtPeriodsShort
  505. }
  506. if len(trans.FmtPeriodsWide) == 0 && inheritedFound {
  507. trans.FmtPeriodsWide = inherited.FmtPeriodsWide
  508. }
  509. if len(trans.FmtPeriodsWide) == 0 && baseFound {
  510. trans.FmtPeriodsWide = base.FmtPeriodsWide
  511. }
  512. // era values
  513. if len(trans.FmtErasAbbreviated) == 0 && inheritedFound {
  514. trans.FmtErasAbbreviated = inherited.FmtErasAbbreviated
  515. }
  516. if len(trans.FmtErasAbbreviated) == 0 && baseFound {
  517. trans.FmtErasAbbreviated = base.FmtErasAbbreviated
  518. }
  519. if len(trans.FmtErasNarrow) == 0 && inheritedFound {
  520. trans.FmtErasNarrow = inherited.FmtErasNarrow
  521. }
  522. if len(trans.FmtErasNarrow) == 0 && baseFound {
  523. trans.FmtErasNarrow = base.FmtErasNarrow
  524. }
  525. if len(trans.FmtErasWide) == 0 && inheritedFound {
  526. trans.FmtErasWide = inherited.FmtErasWide
  527. }
  528. if len(trans.FmtErasWide) == 0 && baseFound {
  529. trans.FmtErasWide = base.FmtErasWide
  530. }
  531. ldml := cldr.RawLDML(trans.Locale)
  532. currencies := make([]string, len(globalCurrencies), len(globalCurrencies))
  533. var kval string
  534. for k, v := range globCurrencyIdxMap {
  535. kval = k
  536. // if kval[:len(kval)-1] != " " {
  537. // kval += " "
  538. // }
  539. currencies[v] = kval
  540. }
  541. // some just have no data...
  542. if ldml.Numbers != nil {
  543. if ldml.Numbers.Currencies != nil {
  544. for _, currency := range ldml.Numbers.Currencies.Currency {
  545. if len(currency.Symbol) == 0 {
  546. continue
  547. }
  548. if len(currency.Symbol[0].Data()) == 0 {
  549. continue
  550. }
  551. if len(currency.Type) == 0 {
  552. continue
  553. }
  554. currencies[globCurrencyIdxMap[currency.Type]] = currency.Symbol[0].Data()
  555. }
  556. }
  557. }
  558. trans.Currencies = fmt.Sprintf("%#v", currencies)
  559. // timezones
  560. if (trans.timezones == nil || len(trans.timezones) == 0) && inheritedFound {
  561. trans.timezones = inherited.timezones
  562. }
  563. if (trans.timezones == nil || len(trans.timezones) == 0) && baseFound {
  564. trans.timezones = base.timezones
  565. }
  566. // make sure all inherited timezones are part of sub locale timezones
  567. if inheritedFound {
  568. var ok bool
  569. for k, v := range inherited.timezones {
  570. if _, ok = trans.timezones[k]; ok {
  571. continue
  572. }
  573. trans.timezones[k] = v
  574. }
  575. }
  576. // make sure all base timezones are part of sub locale timezones
  577. if baseFound {
  578. var ok bool
  579. for k, v := range base.timezones {
  580. if _, ok = trans.timezones[k]; ok {
  581. continue
  582. }
  583. trans.timezones[k] = v
  584. }
  585. }
  586. applyOverrides(trans)
  587. parseDecimalNumberFormat(trans)
  588. parsePercentNumberFormat(trans)
  589. parseCurrencyNumberFormat(trans)
  590. }
  591. for _, trans := range translators {
  592. fmt.Println("Final Processing:", trans.Locale)
  593. // if it's still nill.....
  594. if trans.timezones == nil {
  595. trans.timezones = make(map[string]*zoneAbbrev)
  596. }
  597. tz := make(map[string]string) // key = abbrev locale eg. EST, EDT, MST, PST... value = long locale eg. Eastern Standard Time, Pacific Time.....
  598. for k, v := range timezones {
  599. ttz, ok := trans.timezones[k]
  600. if !ok {
  601. ttz = v
  602. trans.timezones[k] = v
  603. }
  604. tz[v.standard] = ttz.standard
  605. tz[v.daylight] = ttz.daylight
  606. }
  607. trans.FmtTimezones = fmt.Sprintf("%#v", tz)
  608. if len(trans.TimeSeparator) == 0 {
  609. trans.TimeSeparator = ":"
  610. }
  611. trans.FmtDateShort, trans.FmtDateMedium, trans.FmtDateLong, trans.FmtDateFull = parseDateFormats(trans, trans.FmtDateShort, trans.FmtDateMedium, trans.FmtDateLong, trans.FmtDateFull)
  612. trans.FmtTimeShort, trans.FmtTimeMedium, trans.FmtTimeLong, trans.FmtTimeFull = parseDateFormats(trans, trans.FmtTimeShort, trans.FmtTimeMedium, trans.FmtTimeLong, trans.FmtTimeFull)
  613. }
  614. }
  615. // preprocesses maps, array etc... just requires multiple passes no choice....
  616. func preProcess(cldrVar *cldr.CLDR) {
  617. for _, l := range cldrVar.Locales() {
  618. fmt.Println("Pre Processing:", l)
  619. split := strings.SplitN(l, "_", 2)
  620. baseLocale := split[0]
  621. // inheritedLocale := baseLocale
  622. // // one of the inherited english locales
  623. // // http://cldr.unicode.org/development/development-process/design-proposals/english-inheritance
  624. // if l == "en_001" || l == "en_GB" {
  625. // inheritedLocale = l
  626. // }
  627. trans := &translator{
  628. Locale: l,
  629. BaseLocale: baseLocale,
  630. // InheritedLocale: inheritedLocale,
  631. }
  632. // if is a base locale
  633. if len(split) == 1 {
  634. baseTranslators[baseLocale] = trans
  635. }
  636. // baseTranslators[l] = trans
  637. // baseTranslators[baseLocale] = trans // allowing for unofficial fallback if none exists
  638. translators[l] = trans
  639. // get number, currency and datetime symbols
  640. // number values
  641. ldml := cldrVar.RawLDML(l)
  642. // some just have no data...
  643. if ldml.Numbers != nil {
  644. if len(ldml.Numbers.Symbols) > 0 {
  645. symbol := ldml.Numbers.Symbols[0]
  646. // Try to get the default numbering system instead of the first one
  647. systems := ldml.Numbers.DefaultNumberingSystem
  648. // There shouldn't really be more than one DefaultNumberingSystem
  649. if len(systems) > 0 {
  650. if dns := systems[0].Data(); dns != "" {
  651. for k := range ldml.Numbers.Symbols {
  652. if ldml.Numbers.Symbols[k].NumberSystem == dns {
  653. symbol = ldml.Numbers.Symbols[k]
  654. break
  655. }
  656. }
  657. }
  658. }
  659. if len(symbol.Decimal) > 0 {
  660. trans.Decimal = symbol.Decimal[0].Data()
  661. }
  662. if len(symbol.Group) > 0 {
  663. trans.Group = symbol.Group[0].Data()
  664. }
  665. if len(symbol.MinusSign) > 0 {
  666. trans.Minus = symbol.MinusSign[0].Data()
  667. }
  668. if len(symbol.PercentSign) > 0 {
  669. trans.Percent = symbol.PercentSign[0].Data()
  670. }
  671. if len(symbol.PerMille) > 0 {
  672. trans.PerMille = symbol.PerMille[0].Data()
  673. }
  674. if len(symbol.TimeSeparator) > 0 {
  675. trans.TimeSeparator = symbol.TimeSeparator[0].Data()
  676. }
  677. if len(symbol.Infinity) > 0 {
  678. trans.Infinity = symbol.Infinity[0].Data()
  679. }
  680. }
  681. if ldml.Numbers.Currencies != nil {
  682. for _, currency := range ldml.Numbers.Currencies.Currency {
  683. if len(strings.TrimSpace(currency.Type)) == 0 {
  684. continue
  685. }
  686. globalCurrenciesMap[currency.Type] = struct{}{}
  687. }
  688. }
  689. if len(ldml.Numbers.DecimalFormats) > 0 && len(ldml.Numbers.DecimalFormats[0].DecimalFormatLength) > 0 {
  690. for _, dfl := range ldml.Numbers.DecimalFormats[0].DecimalFormatLength {
  691. if len(dfl.Type) == 0 {
  692. trans.DecimalNumberFormat = dfl.DecimalFormat[0].Pattern[0].Data()
  693. break
  694. }
  695. }
  696. }
  697. if len(ldml.Numbers.PercentFormats) > 0 && len(ldml.Numbers.PercentFormats[0].PercentFormatLength) > 0 {
  698. for _, dfl := range ldml.Numbers.PercentFormats[0].PercentFormatLength {
  699. if len(dfl.Type) == 0 {
  700. trans.PercentNumberFormat = dfl.PercentFormat[0].Pattern[0].Data()
  701. break
  702. }
  703. }
  704. }
  705. if len(ldml.Numbers.CurrencyFormats) > 0 && len(ldml.Numbers.CurrencyFormats[0].CurrencyFormatLength) > 0 {
  706. if len(ldml.Numbers.CurrencyFormats[0].CurrencyFormatLength[0].CurrencyFormat) > 1 {
  707. split := strings.SplitN(ldml.Numbers.CurrencyFormats[0].CurrencyFormatLength[0].CurrencyFormat[1].Pattern[0].Data(), ";", 2)
  708. trans.CurrencyNumberFormat = split[0]
  709. if len(split) > 1 && len(split[1]) > 0 {
  710. trans.NegativeCurrencyNumberFormat = split[1]
  711. } else {
  712. trans.NegativeCurrencyNumberFormat = trans.CurrencyNumberFormat
  713. }
  714. } else {
  715. trans.CurrencyNumberFormat = ldml.Numbers.CurrencyFormats[0].CurrencyFormatLength[0].CurrencyFormat[0].Pattern[0].Data()
  716. trans.NegativeCurrencyNumberFormat = trans.CurrencyNumberFormat
  717. }
  718. }
  719. }
  720. if ldml.Dates != nil {
  721. if ldml.Dates.TimeZoneNames != nil {
  722. for _, zone := range ldml.Dates.TimeZoneNames.Metazone {
  723. for _, short := range zone.Short {
  724. if len(short.Standard) > 0 {
  725. za, ok := timezones[zone.Type]
  726. if !ok {
  727. za = new(zoneAbbrev)
  728. timezones[zone.Type] = za
  729. }
  730. za.standard = short.Standard[0].Data()
  731. }
  732. if len(short.Daylight) > 0 {
  733. za, ok := timezones[zone.Type]
  734. if !ok {
  735. za = new(zoneAbbrev)
  736. timezones[zone.Type] = za
  737. }
  738. za.daylight = short.Daylight[0].Data()
  739. }
  740. }
  741. for _, long := range zone.Long {
  742. if trans.timezones == nil {
  743. trans.timezones = make(map[string]*zoneAbbrev)
  744. }
  745. if len(long.Standard) > 0 {
  746. za, ok := trans.timezones[zone.Type]
  747. if !ok {
  748. za = new(zoneAbbrev)
  749. trans.timezones[zone.Type] = za
  750. }
  751. za.standard = long.Standard[0].Data()
  752. }
  753. za, ok := trans.timezones[zone.Type]
  754. if !ok {
  755. za = new(zoneAbbrev)
  756. trans.timezones[zone.Type] = za
  757. }
  758. if len(long.Daylight) > 0 {
  759. za.daylight = long.Daylight[0].Data()
  760. } else {
  761. za.daylight = za.standard
  762. }
  763. }
  764. }
  765. }
  766. if ldml.Dates.Calendars != nil {
  767. var calendar *cldr.Calendar
  768. for _, cal := range ldml.Dates.Calendars.Calendar {
  769. if cal.Type == "gregorian" {
  770. calendar = cal
  771. }
  772. }
  773. if calendar != nil {
  774. if calendar.DateFormats != nil {
  775. for _, datefmt := range calendar.DateFormats.DateFormatLength {
  776. switch datefmt.Type {
  777. case "full":
  778. trans.FmtDateFull = datefmt.DateFormat[0].Pattern[0].Data()
  779. case "long":
  780. trans.FmtDateLong = datefmt.DateFormat[0].Pattern[0].Data()
  781. case "medium":
  782. trans.FmtDateMedium = datefmt.DateFormat[0].Pattern[0].Data()
  783. case "short":
  784. trans.FmtDateShort = datefmt.DateFormat[0].Pattern[0].Data()
  785. }
  786. }
  787. }
  788. if calendar.TimeFormats != nil {
  789. for _, datefmt := range calendar.TimeFormats.TimeFormatLength {
  790. switch datefmt.Type {
  791. case "full":
  792. trans.FmtTimeFull = datefmt.TimeFormat[0].Pattern[0].Data()
  793. case "long":
  794. trans.FmtTimeLong = datefmt.TimeFormat[0].Pattern[0].Data()
  795. case "medium":
  796. trans.FmtTimeMedium = datefmt.TimeFormat[0].Pattern[0].Data()
  797. case "short":
  798. trans.FmtTimeShort = datefmt.TimeFormat[0].Pattern[0].Data()
  799. }
  800. }
  801. }
  802. if calendar.Months != nil {
  803. // month context starts at 'format', but there is also has 'stand-alone'
  804. // I'm making the decision to use the 'stand-alone' if, and only if,
  805. // the value does not exist in the 'format' month context
  806. var abbrSet, narrSet, wideSet bool
  807. for _, monthctx := range calendar.Months.MonthContext {
  808. for _, months := range monthctx.MonthWidth {
  809. var monthData []string
  810. for _, m := range months.Month {
  811. if len(m.Data()) == 0 {
  812. continue
  813. }
  814. switch m.Type {
  815. case "1":
  816. monthData = append(monthData, m.Data())
  817. case "2":
  818. monthData = append(monthData, m.Data())
  819. case "3":
  820. monthData = append(monthData, m.Data())
  821. case "4":
  822. monthData = append(monthData, m.Data())
  823. case "5":
  824. monthData = append(monthData, m.Data())
  825. case "6":
  826. monthData = append(monthData, m.Data())
  827. case "7":
  828. monthData = append(monthData, m.Data())
  829. case "8":
  830. monthData = append(monthData, m.Data())
  831. case "9":
  832. monthData = append(monthData, m.Data())
  833. case "10":
  834. monthData = append(monthData, m.Data())
  835. case "11":
  836. monthData = append(monthData, m.Data())
  837. case "12":
  838. monthData = append(monthData, m.Data())
  839. }
  840. }
  841. if len(monthData) > 0 {
  842. // making array indexes line up with month values
  843. // so I'll have an extra empty value, it's way faster
  844. // than a switch over all type values...
  845. monthData = append(make([]string, 1, len(monthData)+1), monthData...)
  846. switch months.Type {
  847. case "abbreviated":
  848. if !abbrSet {
  849. abbrSet = true
  850. trans.FmtMonthsAbbreviated = fmt.Sprintf("%#v", monthData)
  851. }
  852. case "narrow":
  853. if !narrSet {
  854. narrSet = true
  855. trans.FmtMonthsNarrow = fmt.Sprintf("%#v", monthData)
  856. }
  857. case "wide":
  858. if !wideSet {
  859. wideSet = true
  860. trans.FmtMonthsWide = fmt.Sprintf("%#v", monthData)
  861. }
  862. }
  863. }
  864. }
  865. }
  866. }
  867. if calendar.Days != nil {
  868. // day context starts at 'format', but there is also has 'stand-alone'
  869. // I'm making the decision to use the 'stand-alone' if, and only if,
  870. // the value does not exist in the 'format' day context
  871. var abbrSet, narrSet, shortSet, wideSet bool
  872. for _, dayctx := range calendar.Days.DayContext {
  873. for _, days := range dayctx.DayWidth {
  874. var dayData []string
  875. for _, d := range days.Day {
  876. switch d.Type {
  877. case "sun":
  878. dayData = append(dayData, d.Data())
  879. case "mon":
  880. dayData = append(dayData, d.Data())
  881. case "tue":
  882. dayData = append(dayData, d.Data())
  883. case "wed":
  884. dayData = append(dayData, d.Data())
  885. case "thu":
  886. dayData = append(dayData, d.Data())
  887. case "fri":
  888. dayData = append(dayData, d.Data())
  889. case "sat":
  890. dayData = append(dayData, d.Data())
  891. }
  892. }
  893. if len(dayData) > 0 {
  894. switch days.Type {
  895. case "abbreviated":
  896. if !abbrSet {
  897. abbrSet = true
  898. trans.FmtDaysAbbreviated = fmt.Sprintf("%#v", dayData)
  899. }
  900. case "narrow":
  901. if !narrSet {
  902. narrSet = true
  903. trans.FmtDaysNarrow = fmt.Sprintf("%#v", dayData)
  904. }
  905. case "short":
  906. if !shortSet {
  907. shortSet = true
  908. trans.FmtDaysShort = fmt.Sprintf("%#v", dayData)
  909. }
  910. case "wide":
  911. if !wideSet {
  912. wideSet = true
  913. trans.FmtDaysWide = fmt.Sprintf("%#v", dayData)
  914. }
  915. }
  916. }
  917. }
  918. }
  919. }
  920. if calendar.DayPeriods != nil {
  921. // day periods context starts at 'format', but there is also has 'stand-alone'
  922. // I'm making the decision to use the 'stand-alone' if, and only if,
  923. // the value does not exist in the 'format' day period context
  924. var abbrSet, narrSet, shortSet, wideSet bool
  925. for _, ctx := range calendar.DayPeriods.DayPeriodContext {
  926. for _, width := range ctx.DayPeriodWidth {
  927. // [0] = AM
  928. // [0] = PM
  929. ampm := make([]string, 2, 2)
  930. for _, d := range width.DayPeriod {
  931. if d.Type == "am" {
  932. ampm[0] = d.Data()
  933. continue
  934. }
  935. if d.Type == "pm" {
  936. ampm[1] = d.Data()
  937. }
  938. }
  939. switch width.Type {
  940. case "abbreviated":
  941. if !abbrSet {
  942. abbrSet = true
  943. trans.FmtPeriodsAbbreviated = fmt.Sprintf("%#v", ampm)
  944. }
  945. case "narrow":
  946. if !narrSet {
  947. narrSet = true
  948. trans.FmtPeriodsNarrow = fmt.Sprintf("%#v", ampm)
  949. }
  950. case "short":
  951. if !shortSet {
  952. shortSet = true
  953. trans.FmtPeriodsShort = fmt.Sprintf("%#v", ampm)
  954. }
  955. case "wide":
  956. if !wideSet {
  957. wideSet = true
  958. trans.FmtPeriodsWide = fmt.Sprintf("%#v", ampm)
  959. }
  960. }
  961. }
  962. }
  963. }
  964. if calendar.Eras != nil {
  965. // [0] = BC
  966. // [0] = AD
  967. abbrev := make([]string, 2, 2)
  968. narr := make([]string, 2, 2)
  969. wide := make([]string, 2, 2)
  970. if calendar.Eras.EraAbbr != nil {
  971. if len(calendar.Eras.EraAbbr.Era) == 4 {
  972. abbrev[0] = calendar.Eras.EraAbbr.Era[0].Data()
  973. abbrev[1] = calendar.Eras.EraAbbr.Era[2].Data()
  974. } else if len(calendar.Eras.EraAbbr.Era) == 2 {
  975. abbrev[0] = calendar.Eras.EraAbbr.Era[0].Data()
  976. abbrev[1] = calendar.Eras.EraAbbr.Era[1].Data()
  977. }
  978. }
  979. if calendar.Eras.EraNarrow != nil {
  980. if len(calendar.Eras.EraNarrow.Era) == 4 {
  981. narr[0] = calendar.Eras.EraNarrow.Era[0].Data()
  982. narr[1] = calendar.Eras.EraNarrow.Era[2].Data()
  983. } else if len(calendar.Eras.EraNarrow.Era) == 2 {
  984. narr[0] = calendar.Eras.EraNarrow.Era[0].Data()
  985. narr[1] = calendar.Eras.EraNarrow.Era[1].Data()
  986. }
  987. }
  988. if calendar.Eras.EraNames != nil {
  989. if len(calendar.Eras.EraNames.Era) == 4 {
  990. wide[0] = calendar.Eras.EraNames.Era[0].Data()
  991. wide[1] = calendar.Eras.EraNames.Era[2].Data()
  992. } else if len(calendar.Eras.EraNames.Era) == 2 {
  993. wide[0] = calendar.Eras.EraNames.Era[0].Data()
  994. wide[1] = calendar.Eras.EraNames.Era[1].Data()
  995. }
  996. }
  997. trans.FmtErasAbbreviated = fmt.Sprintf("%#v", abbrev)
  998. trans.FmtErasNarrow = fmt.Sprintf("%#v", narr)
  999. trans.FmtErasWide = fmt.Sprintf("%#v", wide)
  1000. }
  1001. }
  1002. }
  1003. }
  1004. }
  1005. for k := range globalCurrenciesMap {
  1006. globalCurrencies = append(globalCurrencies, k)
  1007. }
  1008. sort.Strings(globalCurrencies)
  1009. for i, loc := range globalCurrencies {
  1010. globCurrencyIdxMap[loc] = i
  1011. }
  1012. }
  1013. func parseDateFormats(trans *translator, shortFormat, mediumFormat, longFormat, fullFormat string) (short, medium, long, full string) {
  1014. // Short Date Parsing
  1015. short = parseDateTimeFormat(trans.BaseLocale, shortFormat, 2)
  1016. medium = parseDateTimeFormat(trans.BaseLocale, mediumFormat, 2)
  1017. long = parseDateTimeFormat(trans.BaseLocale, longFormat, 1)
  1018. full = parseDateTimeFormat(trans.BaseLocale, fullFormat, 0)
  1019. // End Short Data Parsing
  1020. return
  1021. }
  1022. func parseDateTimeFormat(baseLocale, format string, eraScore uint8) (results string) {
  1023. // rules:
  1024. // y = four digit year
  1025. // yy = two digit year
  1026. // var b []byte
  1027. var inConstantText bool
  1028. var start int
  1029. for i := 0; i < len(format); i++ {
  1030. switch format[i] {
  1031. // time separator
  1032. case ':':
  1033. if inConstantText {
  1034. inConstantText = false
  1035. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1036. }
  1037. results += "b = append(b, " + baseLocale + ".timeSeparator...)"
  1038. case '\'':
  1039. i++
  1040. startI := i
  1041. // peek to see if ''
  1042. if len(format) != i && format[i] == '\'' {
  1043. if inConstantText {
  1044. inConstantText = false
  1045. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i-1])) + "...)\n"
  1046. } else {
  1047. inConstantText = true
  1048. start = i
  1049. }
  1050. continue
  1051. }
  1052. // not '' so whatever comes between '' is constant
  1053. if len(format) != i {
  1054. // advance i to the next single quote + 1
  1055. for ; i < len(format); i++ {
  1056. if format[i] == '\'' {
  1057. if inConstantText {
  1058. inConstantText = false
  1059. b := []byte(format[start : startI-1])
  1060. b = append(b, []byte(format[startI:i])...)
  1061. results += "b = append(b, " + fmt.Sprintf("%#v", b) + "...)\n"
  1062. } else {
  1063. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[startI:i])) + "...)\n"
  1064. }
  1065. break
  1066. }
  1067. }
  1068. }
  1069. // 24 hour
  1070. case 'H':
  1071. if inConstantText {
  1072. inConstantText = false
  1073. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1074. }
  1075. // peek
  1076. // two digit hour required?
  1077. if len(format) != i+1 && format[i+1] == 'H' {
  1078. i++
  1079. results += `
  1080. if t.Hour() < 10 {
  1081. b = append(b, '0')
  1082. }
  1083. `
  1084. }
  1085. results += "b = strconv.AppendInt(b, int64(t.Hour()), 10)\n"
  1086. // hour
  1087. case 'h':
  1088. if inConstantText {
  1089. inConstantText = false
  1090. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1091. }
  1092. results += `
  1093. h := t.Hour()
  1094. if h > 12 {
  1095. h -= 12
  1096. }
  1097. `
  1098. // peek
  1099. // two digit hour required?
  1100. if len(format) != i+1 && format[i+1] == 'h' {
  1101. i++
  1102. results += `
  1103. if h < 10 {
  1104. b = append(b, '0')
  1105. }
  1106. `
  1107. }
  1108. results += "b = strconv.AppendInt(b, int64(h), 10)\n"
  1109. // minute
  1110. case 'm':
  1111. if inConstantText {
  1112. inConstantText = false
  1113. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1114. }
  1115. // peek
  1116. // two digit minute required?
  1117. if len(format) != i+1 && format[i+1] == 'm' {
  1118. i++
  1119. results += `
  1120. if t.Minute() < 10 {
  1121. b = append(b, '0')
  1122. }
  1123. `
  1124. }
  1125. results += "b = strconv.AppendInt(b, int64(t.Minute()), 10)\n"
  1126. // second
  1127. case 's':
  1128. if inConstantText {
  1129. inConstantText = false
  1130. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1131. }
  1132. // peek
  1133. // two digit minute required?
  1134. if len(format) != i+1 && format[i+1] == 's' {
  1135. i++
  1136. results += `
  1137. if t.Second() < 10 {
  1138. b = append(b, '0')
  1139. }
  1140. `
  1141. }
  1142. results += "b = strconv.AppendInt(b, int64(t.Second()), 10)\n"
  1143. // day period
  1144. case 'a':
  1145. if inConstantText {
  1146. inConstantText = false
  1147. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1148. }
  1149. // only used with 'h', patterns should not contains 'a' without 'h' so not checking
  1150. // choosing to use abbreviated, didn't see any rules about which should be used with which
  1151. // date format....
  1152. results += `
  1153. if t.Hour() < 12 {
  1154. b = append(b, ` + baseLocale + `.periodsAbbreviated[0]...)
  1155. } else {
  1156. b = append(b, ` + baseLocale + `.periodsAbbreviated[1]...)
  1157. }
  1158. `
  1159. // timezone
  1160. case 'z', 'v':
  1161. if inConstantText {
  1162. inConstantText = false
  1163. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1164. }
  1165. // consume multiple, only handling Abbrev tz from time.Time for the moment...
  1166. var count int
  1167. if format[i] == 'z' {
  1168. for j := i; j < len(format); j++ {
  1169. if format[j] == 'z' {
  1170. count++
  1171. } else {
  1172. break
  1173. }
  1174. }
  1175. }
  1176. if format[i] == 'v' {
  1177. for j := i; j < len(format); j++ {
  1178. if format[j] == 'v' {
  1179. count++
  1180. } else {
  1181. break
  1182. }
  1183. }
  1184. }
  1185. i += count - 1
  1186. // using the timezone on the Go time object, eg. EST, EDT, MST.....
  1187. if count < 4 {
  1188. results += `
  1189. tz, _ := t.Zone()
  1190. b = append(b, tz...)
  1191. `
  1192. } else {
  1193. results += `
  1194. tz, _ := t.Zone()
  1195. if btz, ok := ` + baseLocale + `.timezones[tz]; ok {
  1196. b = append(b, btz...)
  1197. } else {
  1198. b = append(b, tz...)
  1199. }
  1200. `
  1201. }
  1202. // day
  1203. case 'd':
  1204. if inConstantText {
  1205. inConstantText = false
  1206. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1207. }
  1208. // peek
  1209. // two digit day required?
  1210. if len(format) != i+1 && format[i+1] == 'd' {
  1211. i++
  1212. results += `
  1213. if t.Day() < 10 {
  1214. b = append(b, '0')
  1215. }
  1216. `
  1217. }
  1218. results += "b = strconv.AppendInt(b, int64(t.Day()), 10)\n"
  1219. // month
  1220. case 'M':
  1221. if inConstantText {
  1222. inConstantText = false
  1223. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1224. }
  1225. var count int
  1226. // count # of M's
  1227. for j := i; j < len(format); j++ {
  1228. if format[j] == 'M' {
  1229. count++
  1230. } else {
  1231. break
  1232. }
  1233. }
  1234. switch count {
  1235. // Numeric form, at least 1 digit
  1236. case 1:
  1237. results += "b = strconv.AppendInt(b, int64(t.Month()), 10)\n"
  1238. // Number form, at least 2 digits (padding with 0)
  1239. case 2:
  1240. results += `
  1241. if t.Month() < 10 {
  1242. b = append(b, '0')
  1243. }
  1244. b = strconv.AppendInt(b, int64(t.Month()), 10)
  1245. `
  1246. // Abbreviated form
  1247. case 3:
  1248. results += "b = append(b, " + baseLocale + ".monthsAbbreviated[t.Month()]...)\n"
  1249. // Full/Wide form
  1250. case 4:
  1251. results += "b = append(b, " + baseLocale + ".monthsWide[t.Month()]...)\n"
  1252. // Narrow form - only used in where context makes it clear, such as headers in a calendar.
  1253. // Should be one character wherever possible.
  1254. case 5:
  1255. results += "b = append(b, " + baseLocale + ".monthsNarrow[t.Month()]...)\n"
  1256. }
  1257. // skip over M's
  1258. i += count - 1
  1259. // year
  1260. case 'y':
  1261. if inConstantText {
  1262. inConstantText = false
  1263. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1264. }
  1265. // peek
  1266. // two digit year
  1267. if len(format) != i+1 && format[i+1] == 'y' {
  1268. i++
  1269. results += `
  1270. if t.Year() > 9 {
  1271. b = append(b, strconv.Itoa(t.Year())[2:]...)
  1272. } else {
  1273. b = append(b, strconv.Itoa(t.Year())[1:]...)
  1274. }
  1275. `
  1276. } else {
  1277. // four digit year
  1278. results += `
  1279. if t.Year() > 0 {
  1280. b = strconv.AppendInt(b, int64(t.Year()), 10)
  1281. } else {
  1282. b = strconv.AppendInt(b, int64(-t.Year()), 10)
  1283. }
  1284. `
  1285. }
  1286. // weekday
  1287. // I know I only see 'EEEE' in the xml, but just in case handled all posibilities
  1288. case 'E':
  1289. if inConstantText {
  1290. inConstantText = false
  1291. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1292. }
  1293. var count int
  1294. // count # of E's
  1295. for j := i; j < len(format); j++ {
  1296. if format[j] == 'E' {
  1297. count++
  1298. } else {
  1299. break
  1300. }
  1301. }
  1302. switch count {
  1303. // Narrow
  1304. case 1:
  1305. results += "b = append(b, " + baseLocale + ".daysNarrow[t.Weekday()]...)\n"
  1306. // Short
  1307. case 2:
  1308. results += "b = append(b, " + baseLocale + ".daysShort[t.Weekday()]...)\n"
  1309. // Abbreviated
  1310. case 3:
  1311. results += "b = append(b, " + baseLocale + ".daysAbbreviated[t.Weekday()]...)\n"
  1312. // Full/Wide
  1313. case 4:
  1314. results += "b = append(b, " + baseLocale + ".daysWide[t.Weekday()]...)\n"
  1315. }
  1316. // skip over E's
  1317. i += count - 1
  1318. // era eg. AD, BC
  1319. case 'G':
  1320. if inConstantText {
  1321. inConstantText = false
  1322. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:i])) + "...)\n"
  1323. }
  1324. switch eraScore {
  1325. case 0:
  1326. results += `
  1327. if t.Year() < 0 {
  1328. b = append(b, ` + baseLocale + `.erasWide[0]...)
  1329. } else {
  1330. b = append(b, ` + baseLocale + `.erasWide[1]...)
  1331. }
  1332. `
  1333. case 1, 2:
  1334. results += `
  1335. if t.Year() < 0 {
  1336. b = append(b, ` + baseLocale + `.erasAbbreviated[0]...)
  1337. } else {
  1338. b = append(b, ` + baseLocale + `.erasAbbreviated[1]...)
  1339. }
  1340. `
  1341. }
  1342. default:
  1343. // append all non matched text as they are constants
  1344. if !inConstantText {
  1345. inConstantText = true
  1346. start = i
  1347. }
  1348. }
  1349. }
  1350. // if we were inConstantText when the string ended, add what's left.
  1351. if inConstantText {
  1352. // inContantText = false
  1353. results += "b = append(b, " + fmt.Sprintf("%#v", []byte(format[start:])) + "...)\n"
  1354. }
  1355. return
  1356. }
  1357. func parseCurrencyNumberFormat(trans *translator) {
  1358. if len(trans.CurrencyNumberFormat) == 0 {
  1359. return
  1360. }
  1361. trans.FmtCurrencyExists = true
  1362. negativeEqual := trans.CurrencyNumberFormat == trans.NegativeCurrencyNumberFormat
  1363. match := groupLenRegex.FindString(trans.CurrencyNumberFormat)
  1364. if len(match) > 0 {
  1365. trans.FmtCurrencyGroupLen = len(match) - 2
  1366. }
  1367. match = requiredDecimalRegex.FindString(trans.CurrencyNumberFormat)
  1368. if len(match) > 0 {
  1369. trans.FmtCurrencyMinDecimalLen = len(match) - 1
  1370. }
  1371. match = secondaryGroupLenRegex.FindString(trans.CurrencyNumberFormat)
  1372. if len(match) > 0 {
  1373. trans.FmtCurrencySecondaryGroupLen = len(match) - 2
  1374. }
  1375. idx := 0
  1376. for idx = 0; idx < len(trans.CurrencyNumberFormat); idx++ {
  1377. if trans.CurrencyNumberFormat[idx] == '#' || trans.CurrencyNumberFormat[idx] == '0' {
  1378. trans.FmtCurrencyPrefix = trans.CurrencyNumberFormat[:idx]
  1379. break
  1380. }
  1381. }
  1382. for idx = len(trans.CurrencyNumberFormat) - 1; idx >= 0; idx-- {
  1383. if trans.CurrencyNumberFormat[idx] == '#' || trans.CurrencyNumberFormat[idx] == '0' {
  1384. idx++
  1385. trans.FmtCurrencySuffix = trans.CurrencyNumberFormat[idx:]
  1386. break
  1387. }
  1388. }
  1389. for idx = 0; idx < len(trans.FmtCurrencyPrefix); idx++ {
  1390. if trans.FmtCurrencyPrefix[idx] == '¤' {
  1391. trans.FmtCurrencyInPrefix = true
  1392. trans.FmtCurrencyPrefix = strings.Replace(trans.FmtCurrencyPrefix, string(trans.FmtCurrencyPrefix[idx]), "", 1)
  1393. if idx == 0 {
  1394. trans.FmtCurrencyLeft = true
  1395. } else {
  1396. trans.FmtCurrencyLeft = false
  1397. }
  1398. break
  1399. }
  1400. }
  1401. for idx = 0; idx < len(trans.FmtCurrencySuffix); idx++ {
  1402. if trans.FmtCurrencySuffix[idx] == '¤' {
  1403. trans.FmtCurrencyInPrefix = false
  1404. trans.FmtCurrencySuffix = strings.Replace(trans.FmtCurrencySuffix, string(trans.FmtCurrencySuffix[idx]), "", 1)
  1405. if idx == 0 {
  1406. trans.FmtCurrencyLeft = true
  1407. } else {
  1408. trans.FmtCurrencyLeft = false
  1409. }
  1410. break
  1411. }
  1412. }
  1413. // if len(trans.FmtCurrencyPrefix) > 0 {
  1414. // trans.FmtCurrencyPrefix = fmt.Sprintf("%#v", []byte(trans.FmtCurrencyPrefix))
  1415. // }
  1416. // if len(trans.FmtCurrencySuffix) > 0 {
  1417. // trans.FmtCurrencySuffix = fmt.Sprintf("%#v", []byte(trans.FmtCurrencySuffix))
  1418. // }
  1419. // no need to parse again if true....
  1420. if negativeEqual {
  1421. trans.FmtCurrencyNegativePrefix = trans.FmtCurrencyPrefix
  1422. trans.FmtCurrencyNegativeSuffix = trans.FmtCurrencySuffix
  1423. trans.FmtCurrencyNegativeInPrefix = trans.FmtCurrencyInPrefix
  1424. trans.FmtCurrencyNegativeLeft = trans.FmtCurrencyLeft
  1425. return
  1426. }
  1427. trans.FmtCurrencyNegativeExists = true
  1428. for idx = 0; idx < len(trans.NegativeCurrencyNumberFormat); idx++ {
  1429. if trans.NegativeCurrencyNumberFormat[idx] == '#' || trans.NegativeCurrencyNumberFormat[idx] == '0' {
  1430. trans.FmtCurrencyNegativePrefix = trans.NegativeCurrencyNumberFormat[:idx]
  1431. break
  1432. }
  1433. }
  1434. for idx = len(trans.NegativeCurrencyNumberFormat) - 1; idx >= 0; idx-- {
  1435. if trans.NegativeCurrencyNumberFormat[idx] == '#' || trans.NegativeCurrencyNumberFormat[idx] == '0' {
  1436. idx++
  1437. trans.FmtCurrencyNegativeSuffix = trans.NegativeCurrencyNumberFormat[idx:]
  1438. break
  1439. }
  1440. }
  1441. for idx = 0; idx < len(trans.FmtCurrencyNegativePrefix); idx++ {
  1442. if trans.FmtCurrencyNegativePrefix[idx] == '¤' {
  1443. trans.FmtCurrencyNegativeInPrefix = true
  1444. trans.FmtCurrencyNegativePrefix = strings.Replace(trans.FmtCurrencyNegativePrefix, string(trans.FmtCurrencyNegativePrefix[idx]), "", 1)
  1445. if idx == 0 {
  1446. trans.FmtCurrencyNegativeLeft = true
  1447. } else {
  1448. trans.FmtCurrencyNegativeLeft = false
  1449. }
  1450. break
  1451. }
  1452. }
  1453. for idx = 0; idx < len(trans.FmtCurrencyNegativeSuffix); idx++ {
  1454. if trans.FmtCurrencyNegativeSuffix[idx] == '¤' {
  1455. trans.FmtCurrencyNegativeInPrefix = false
  1456. trans.FmtCurrencyNegativeSuffix = strings.Replace(trans.FmtCurrencyNegativeSuffix, string(trans.FmtCurrencyNegativeSuffix[idx]), "", 1)
  1457. if idx == 0 {
  1458. trans.FmtCurrencyNegativeLeft = true
  1459. } else {
  1460. trans.FmtCurrencyNegativeLeft = false
  1461. }
  1462. break
  1463. }
  1464. }
  1465. // if len(trans.FmtCurrencyNegativePrefix) > 0 {
  1466. // trans.FmtCurrencyNegativePrefix = fmt.Sprintf("%#v", []byte(trans.FmtCurrencyNegativePrefix))
  1467. // }
  1468. // if len(trans.FmtCurrencyNegativeSuffix) > 0 {
  1469. // trans.FmtCurrencyNegativeSuffix = fmt.Sprintf("%#v", []byte(trans.FmtCurrencyNegativeSuffix))
  1470. // }
  1471. return
  1472. }
  1473. func parsePercentNumberFormat(trans *translator) {
  1474. if len(trans.PercentNumberFormat) == 0 {
  1475. return
  1476. }
  1477. trans.FmtPercentExists = true
  1478. match := groupLenPercentRegex.FindString(trans.PercentNumberFormat)
  1479. if len(match) > 0 {
  1480. trans.FmtPercentGroupLen = len(match) - 1
  1481. }
  1482. match = requiredDecimalRegex.FindString(trans.PercentNumberFormat)
  1483. if len(match) > 0 {
  1484. trans.FmtPercentMinDecimalLen = len(match) - 1
  1485. }
  1486. match = secondaryGroupLenRegex.FindString(trans.PercentNumberFormat)
  1487. if len(match) > 0 {
  1488. trans.FmtPercentSecondaryGroupLen = len(match) - 2
  1489. }
  1490. idx := 0
  1491. for idx = 0; idx < len(trans.PercentNumberFormat); idx++ {
  1492. if trans.PercentNumberFormat[idx] == '#' || trans.PercentNumberFormat[idx] == '0' {
  1493. trans.FmtPercentPrefix = trans.PercentNumberFormat[:idx]
  1494. break
  1495. }
  1496. }
  1497. for idx = len(trans.PercentNumberFormat) - 1; idx >= 0; idx-- {
  1498. if trans.PercentNumberFormat[idx] == '#' || trans.PercentNumberFormat[idx] == '0' {
  1499. idx++
  1500. trans.FmtPercentSuffix = trans.PercentNumberFormat[idx:]
  1501. break
  1502. }
  1503. }
  1504. for idx = 0; idx < len(trans.FmtPercentPrefix); idx++ {
  1505. if trans.FmtPercentPrefix[idx] == '%' {
  1506. trans.FmtPercentInPrefix = true
  1507. trans.FmtPercentPrefix = strings.Replace(trans.FmtPercentPrefix, string(trans.FmtPercentPrefix[idx]), "", 1)
  1508. if idx == 0 {
  1509. trans.FmtPercentLeft = true
  1510. } else {
  1511. trans.FmtPercentLeft = false
  1512. }
  1513. break
  1514. }
  1515. }
  1516. for idx = 0; idx < len(trans.FmtPercentSuffix); idx++ {
  1517. if trans.FmtPercentSuffix[idx] == '%' {
  1518. trans.FmtPercentInPrefix = false
  1519. trans.FmtPercentSuffix = strings.Replace(trans.FmtPercentSuffix, string(trans.FmtPercentSuffix[idx]), "", 1)
  1520. if idx == 0 {
  1521. trans.FmtPercentLeft = true
  1522. } else {
  1523. trans.FmtPercentLeft = false
  1524. }
  1525. break
  1526. }
  1527. }
  1528. // if len(trans.FmtPercentPrefix) > 0 {
  1529. // trans.FmtPercentPrefix = fmt.Sprintf("%#v", []byte(trans.FmtPercentPrefix))
  1530. // }
  1531. // if len(trans.FmtPercentSuffix) > 0 {
  1532. // trans.FmtPercentSuffix = fmt.Sprintf("%#v", []byte(trans.FmtPercentSuffix))
  1533. // }
  1534. return
  1535. }
  1536. func parseDecimalNumberFormat(trans *translator) {
  1537. if len(trans.DecimalNumberFormat) == 0 {
  1538. return
  1539. }
  1540. trans.FmtNumberExists = true
  1541. formats := strings.SplitN(trans.DecimalNumberFormat, ";", 2)
  1542. match := groupLenRegex.FindString(formats[0])
  1543. if len(match) > 0 {
  1544. trans.FmtNumberGroupLen = len(match) - 2
  1545. }
  1546. match = requiredDecimalRegex.FindString(formats[0])
  1547. if len(match) > 0 {
  1548. trans.FmtNumberMinDecimalLen = len(match) - 1
  1549. }
  1550. match = secondaryGroupLenRegex.FindString(formats[0])
  1551. if len(match) > 0 {
  1552. trans.FmtNumberSecondaryGroupLen = len(match) - 2
  1553. }
  1554. return
  1555. }
  1556. type sortRank struct {
  1557. Rank uint8
  1558. Value string
  1559. }
  1560. type ByRank []sortRank
  1561. func (a ByRank) Len() int { return len(a) }
  1562. func (a ByRank) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  1563. func (a ByRank) Less(i, j int) bool { return a[i].Rank < a[j].Rank }
  1564. type ByPluralRule []locales.PluralRule
  1565. func (a ByPluralRule) Len() int { return len(a) }
  1566. func (a ByPluralRule) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
  1567. func (a ByPluralRule) Less(i, j int) bool { return a[i] < a[j] }
  1568. // TODO: refine generated code a bit, some combinations end up with same plural rule,
  1569. // could check all at once; but it works and that's step 1 complete
  1570. func parseRangePluralRuleFunc(current *cldr.CLDR, baseLocale string) (results string, plurals string) {
  1571. var pluralRange *struct {
  1572. cldr.Common
  1573. Locales string `xml:"locales,attr"`
  1574. PluralRange []*struct {
  1575. cldr.Common
  1576. Start string `xml:"start,attr"`
  1577. End string `xml:"end,attr"`
  1578. Result string `xml:"result,attr"`
  1579. } `xml:"pluralRange"`
  1580. }
  1581. var pluralArr []locales.PluralRule
  1582. for _, pr := range current.Supplemental().Plurals[1].PluralRanges {
  1583. locs := strings.Split(pr.Locales, " ")
  1584. for _, loc := range locs {
  1585. if loc == baseLocale {
  1586. pluralRange = pr
  1587. }
  1588. }
  1589. }
  1590. // no range plural rules for locale
  1591. if pluralRange == nil {
  1592. plurals = "nil"
  1593. results = "return locales.PluralRuleUnknown"
  1594. return
  1595. }
  1596. mp := make(map[string]struct{})
  1597. // pre-process if all the same
  1598. for _, rule := range pluralRange.PluralRange {
  1599. mp[rule.Result] = struct{}{}
  1600. }
  1601. for k := range mp {
  1602. psI := pluralStringToInt(k)
  1603. pluralArr = append(pluralArr, psI)
  1604. }
  1605. if len(mp) == 1 {
  1606. results += "return locales." + pluralStringToString(pluralRange.PluralRange[0].Result)
  1607. plurals = fmt.Sprintf("%#v", pluralArr)
  1608. return
  1609. }
  1610. multiple := len(pluralRange.PluralRange) > 1
  1611. if multiple {
  1612. results += "start := " + baseLocale + ".CardinalPluralRule(num1, v1)\n"
  1613. results += "end := " + baseLocale + ".CardinalPluralRule(num2, v2)\n\n"
  1614. }
  1615. first := true
  1616. // pre parse for variables
  1617. for i, rule := range pluralRange.PluralRange {
  1618. if i == len(pluralRange.PluralRange)-1 {
  1619. if multiple {
  1620. results += "\n\n"
  1621. }
  1622. results += "return locales." + pluralStringToString(rule.Result)
  1623. continue
  1624. }
  1625. if first {
  1626. results += "if"
  1627. first = false
  1628. } else {
  1629. results += "else if"
  1630. }
  1631. results += " start == locales." + pluralStringToString(rule.Start) + " && end == locales." + pluralStringToString(rule.End) + " {\n return locales." + pluralStringToString(rule.Result) + "\n} "
  1632. }
  1633. if multiple {
  1634. results = "\n" + results + "\n"
  1635. }
  1636. if len(pluralArr) == 0 {
  1637. plurals = "nil"
  1638. } else {
  1639. ints := make([]int, len(pluralArr))
  1640. for i := 0; i < len(pluralArr); i++ {
  1641. ints[i] = int(pluralArr[i])
  1642. }
  1643. sort.Ints(ints)
  1644. for i := 0; i < len(ints); i++ {
  1645. pluralArr[i] = locales.PluralRule(ints[i])
  1646. }
  1647. plurals = fmt.Sprintf("%#v", pluralArr)
  1648. }
  1649. return
  1650. }
  1651. // TODO: cleanup function logic perhaps write a lexer... but it's working right now, and
  1652. // I'm already farther down the rabbit hole than I'd like and so pulling the chute here.
  1653. func parseOrdinalPluralRuleFunc(current *cldr.CLDR, baseLocale string) (results string, plurals string) {
  1654. var prOrdinal *struct {
  1655. cldr.Common
  1656. Locales string "xml:\"locales,attr\""
  1657. PluralRule []*struct {
  1658. cldr.Common
  1659. Count string "xml:\"count,attr\""
  1660. } "xml:\"pluralRule\""
  1661. }
  1662. var pluralArr []locales.PluralRule
  1663. // idx 0 is ordinal rules
  1664. for _, pr := range current.Supplemental().Plurals[0].PluralRules {
  1665. locs := strings.Split(pr.Locales, " ")
  1666. for _, loc := range locs {
  1667. if loc == baseLocale {
  1668. prOrdinal = pr
  1669. // for _, pl := range pr.PluralRule {
  1670. // fmt.Println(pl.Count, pl.Common.Data())
  1671. // }
  1672. }
  1673. }
  1674. }
  1675. // no plural rules for locale
  1676. if prOrdinal == nil {
  1677. plurals = "nil"
  1678. results = "return locales.PluralRuleUnknown"
  1679. return
  1680. }
  1681. vals := make(map[string]struct{})
  1682. first := true
  1683. // pre parse for variables
  1684. for _, rule := range prOrdinal.PluralRule {
  1685. ps1 := pluralStringToString(rule.Count)
  1686. psI := pluralStringToInt(rule.Count)
  1687. pluralArr = append(pluralArr, psI)
  1688. data := strings.Replace(strings.Replace(strings.Replace(strings.TrimSpace(strings.SplitN(rule.Common.Data(), "@", 2)[0]), " = ", " == ", -1), " or ", " || ", -1), " and ", " && ", -1)
  1689. if len(data) == 0 {
  1690. if len(prOrdinal.PluralRule) == 1 {
  1691. results = "return locales." + ps1
  1692. } else {
  1693. results += "\n\nreturn locales." + ps1
  1694. // results += "else {\nreturn locales." + locales.PluralStringToString(rule.Count) + ", nil\n}"
  1695. }
  1696. continue
  1697. }
  1698. // // All need n, so always add
  1699. // if strings.Contains(data, "n") {
  1700. // vals[prVarFuncs["n"]] = struct{}{}
  1701. // }
  1702. if strings.Contains(data, "i") {
  1703. vals[prVarFuncs["i"]] = struct{}{}
  1704. }
  1705. // v is inherently avaialable as an argument
  1706. // if strings.Contains(data, "v") {
  1707. // vals[prVarFuncs["v"]] = struct{}{}
  1708. // }
  1709. if strings.Contains(data, "w") {
  1710. vals[prVarFuncs["w"]] = struct{}{}
  1711. }
  1712. if strings.Contains(data, "f") {
  1713. vals[prVarFuncs["f"]] = struct{}{}
  1714. }
  1715. if strings.Contains(data, "t") {
  1716. vals[prVarFuncs["t"]] = struct{}{}
  1717. }
  1718. if first {
  1719. results += "if "
  1720. first = false
  1721. } else {
  1722. results += "else if "
  1723. }
  1724. stmt := ""
  1725. // real work here
  1726. //
  1727. // split by 'or' then by 'and' allowing to better
  1728. // determine bracketing for formula
  1729. ors := strings.Split(data, "||")
  1730. for _, or := range ors {
  1731. stmt += "("
  1732. ands := strings.Split(strings.TrimSpace(or), "&&")
  1733. for _, and := range ands {
  1734. inArg := false
  1735. pre := ""
  1736. lft := ""
  1737. preOperator := ""
  1738. args := strings.Split(strings.TrimSpace(and), " ")
  1739. for _, a := range args {
  1740. if inArg {
  1741. // check to see if is a value range 2..9
  1742. multiRange := strings.Count(a, "..") > 1
  1743. cargs := strings.Split(strings.TrimSpace(a), ",")
  1744. hasBracket := len(cargs) > 1
  1745. bracketAdded := false
  1746. lastWasRange := false
  1747. for _, carg := range cargs {
  1748. if rng := strings.Split(carg, ".."); len(rng) > 1 {
  1749. if multiRange {
  1750. pre += " ("
  1751. } else {
  1752. pre += " "
  1753. }
  1754. switch preOperator {
  1755. case "==":
  1756. pre += lft + " >= " + rng[0] + " && " + lft + "<=" + rng[1]
  1757. case "!=":
  1758. pre += "(" + lft + " < " + rng[0] + " || " + lft + " > " + rng[1] + ")"
  1759. }
  1760. if multiRange {
  1761. pre += ") || "
  1762. } else {
  1763. pre += " || "
  1764. }
  1765. lastWasRange = true
  1766. continue
  1767. }
  1768. if lastWasRange {
  1769. pre = strings.TrimRight(pre, " || ") + " && "
  1770. }
  1771. lastWasRange = false
  1772. if hasBracket && !bracketAdded {
  1773. pre += "("
  1774. bracketAdded = true
  1775. }
  1776. // single comma separated values
  1777. switch preOperator {
  1778. case "==":
  1779. pre += " " + lft + preOperator + carg + " || "
  1780. case "!=":
  1781. pre += " " + lft + preOperator + carg + " && "
  1782. }
  1783. }
  1784. pre = strings.TrimRight(pre, " || ")
  1785. pre = strings.TrimRight(pre, " && ")
  1786. pre = strings.TrimRight(pre, " || ")
  1787. if hasBracket && bracketAdded {
  1788. pre += ")"
  1789. }
  1790. continue
  1791. }
  1792. if strings.Contains(a, "=") || a == ">" || a == "<" {
  1793. inArg = true
  1794. preOperator = a
  1795. continue
  1796. }
  1797. lft += a
  1798. }
  1799. stmt += pre + " && "
  1800. }
  1801. stmt = strings.TrimRight(stmt, " && ") + ") || "
  1802. }
  1803. stmt = strings.TrimRight(stmt, " || ")
  1804. results += stmt
  1805. results += " {\n"
  1806. // return plural rule here
  1807. results += "return locales." + ps1 + "\n"
  1808. results += "}"
  1809. }
  1810. pre := "\n"
  1811. // always needed
  1812. vals[prVarFuncs["n"]] = struct{}{}
  1813. sorted := make([]sortRank, 0, len(vals))
  1814. for k := range vals {
  1815. switch k[:1] {
  1816. case "n":
  1817. sorted = append(sorted, sortRank{
  1818. Value: prVarFuncs["n"],
  1819. Rank: 1,
  1820. })
  1821. case "i":
  1822. sorted = append(sorted, sortRank{
  1823. Value: prVarFuncs["i"],
  1824. Rank: 2,
  1825. })
  1826. case "w":
  1827. sorted = append(sorted, sortRank{
  1828. Value: prVarFuncs["w"],
  1829. Rank: 3,
  1830. })
  1831. case "f":
  1832. sorted = append(sorted, sortRank{
  1833. Value: prVarFuncs["f"],
  1834. Rank: 4,
  1835. })
  1836. case "t":
  1837. sorted = append(sorted, sortRank{
  1838. Value: prVarFuncs["t"],
  1839. Rank: 5,
  1840. })
  1841. }
  1842. }
  1843. sort.Sort(ByRank(sorted))
  1844. for _, k := range sorted {
  1845. pre += k.Value
  1846. }
  1847. if len(results) == 0 {
  1848. results = "return locales.PluralRuleUnknown"
  1849. } else {
  1850. if !strings.HasPrefix(results, "return") {
  1851. results = manyToSingleVars(results)
  1852. // pre += "\n"
  1853. results = pre + results
  1854. }
  1855. }
  1856. if len(pluralArr) == 0 {
  1857. plurals = "nil"
  1858. } else {
  1859. plurals = fmt.Sprintf("%#v", pluralArr)
  1860. }
  1861. return
  1862. }
  1863. // TODO: cleanup function logic perhaps write a lexer... but it's working right now, and
  1864. // I'm already farther down the rabbit hole than I'd like and so pulling the chute here.
  1865. //
  1866. // updated to also accept actual locale as 'pt_PT' exists in cardinal rules different from 'pt'
  1867. func parseCardinalPluralRuleFunc(current *cldr.CLDR, locale, baseLocale string) (results string, plurals string) {
  1868. var prCardinal *struct {
  1869. cldr.Common
  1870. Locales string "xml:\"locales,attr\""
  1871. PluralRule []*struct {
  1872. cldr.Common
  1873. Count string "xml:\"count,attr\""
  1874. } "xml:\"pluralRule\""
  1875. }
  1876. var pluralArr []locales.PluralRule
  1877. var inBaseLocale bool
  1878. l := locale
  1879. FIND:
  1880. // idx 2 is cardinal rules
  1881. for _, pr := range current.Supplemental().Plurals[2].PluralRules {
  1882. locs := strings.Split(pr.Locales, " ")
  1883. for _, loc := range locs {
  1884. if loc == l {
  1885. prCardinal = pr
  1886. }
  1887. }
  1888. }
  1889. // no plural rules for locale
  1890. if prCardinal == nil {
  1891. if !inBaseLocale {
  1892. inBaseLocale = true
  1893. l = baseLocale
  1894. goto FIND
  1895. }
  1896. plurals = "nil"
  1897. results = "return locales.PluralRuleUnknown"
  1898. return
  1899. }
  1900. vals := make(map[string]struct{})
  1901. first := true
  1902. // pre parse for variables
  1903. for _, rule := range prCardinal.PluralRule {
  1904. ps1 := pluralStringToString(rule.Count)
  1905. psI := pluralStringToInt(rule.Count)
  1906. pluralArr = append(pluralArr, psI)
  1907. data := strings.Replace(strings.Replace(strings.Replace(strings.TrimSpace(strings.SplitN(rule.Common.Data(), "@", 2)[0]), " = ", " == ", -1), " or ", " || ", -1), " and ", " && ", -1)
  1908. if len(data) == 0 {
  1909. if len(prCardinal.PluralRule) == 1 {
  1910. results = "return locales." + ps1
  1911. } else {
  1912. results += "\n\nreturn locales." + ps1
  1913. // results += "else {\nreturn locales." + locales.PluralStringToString(rule.Count) + ", nil\n}"
  1914. }
  1915. continue
  1916. }
  1917. // // All need n, so always add
  1918. // if strings.Contains(data, "n") {
  1919. // vals[prVarFuncs["n"]] = struct{}{}
  1920. // }
  1921. if strings.Contains(data, "i") {
  1922. vals[prVarFuncs["i"]] = struct{}{}
  1923. }
  1924. // v is inherently avaialable as an argument
  1925. // if strings.Contains(data, "v") {
  1926. // vals[prVarFuncs["v"]] = struct{}{}
  1927. // }
  1928. if strings.Contains(data, "w") {
  1929. vals[prVarFuncs["w"]] = struct{}{}
  1930. }
  1931. if strings.Contains(data, "f") {
  1932. vals[prVarFuncs["f"]] = struct{}{}
  1933. }
  1934. if strings.Contains(data, "t") {
  1935. vals[prVarFuncs["t"]] = struct{}{}
  1936. }
  1937. if first {
  1938. results += "if "
  1939. first = false
  1940. } else {
  1941. results += "else if "
  1942. }
  1943. stmt := ""
  1944. // real work here
  1945. //
  1946. // split by 'or' then by 'and' allowing to better
  1947. // determine bracketing for formula
  1948. ors := strings.Split(data, "||")
  1949. for _, or := range ors {
  1950. stmt += "("
  1951. ands := strings.Split(strings.TrimSpace(or), "&&")
  1952. for _, and := range ands {
  1953. inArg := false
  1954. pre := ""
  1955. lft := ""
  1956. preOperator := ""
  1957. args := strings.Split(strings.TrimSpace(and), " ")
  1958. for _, a := range args {
  1959. if inArg {
  1960. // check to see if is a value range 2..9
  1961. multiRange := strings.Count(a, "..") > 1
  1962. cargs := strings.Split(strings.TrimSpace(a), ",")
  1963. hasBracket := len(cargs) > 1
  1964. bracketAdded := false
  1965. lastWasRange := false
  1966. for _, carg := range cargs {
  1967. if rng := strings.Split(carg, ".."); len(rng) > 1 {
  1968. if multiRange {
  1969. pre += " ("
  1970. } else {
  1971. pre += " "
  1972. }
  1973. switch preOperator {
  1974. case "==":
  1975. pre += lft + " >= " + rng[0] + " && " + lft + "<=" + rng[1]
  1976. case "!=":
  1977. pre += "(" + lft + " < " + rng[0] + " || " + lft + " > " + rng[1] + ")"
  1978. }
  1979. if multiRange {
  1980. pre += ") || "
  1981. } else {
  1982. pre += " || "
  1983. }
  1984. lastWasRange = true
  1985. continue
  1986. }
  1987. if lastWasRange {
  1988. pre = strings.TrimRight(pre, " || ") + " && "
  1989. }
  1990. lastWasRange = false
  1991. if hasBracket && !bracketAdded {
  1992. pre += "("
  1993. bracketAdded = true
  1994. }
  1995. // single comma separated values
  1996. switch preOperator {
  1997. case "==":
  1998. pre += " " + lft + preOperator + carg + " || "
  1999. case "!=":
  2000. pre += " " + lft + preOperator + carg + " && "
  2001. }
  2002. }
  2003. pre = strings.TrimRight(pre, " || ")
  2004. pre = strings.TrimRight(pre, " && ")
  2005. pre = strings.TrimRight(pre, " || ")
  2006. if hasBracket && bracketAdded {
  2007. pre += ")"
  2008. }
  2009. continue
  2010. }
  2011. if strings.Contains(a, "=") || a == ">" || a == "<" {
  2012. inArg = true
  2013. preOperator = a
  2014. continue
  2015. }
  2016. lft += a
  2017. }
  2018. stmt += pre + " && "
  2019. }
  2020. stmt = strings.TrimRight(stmt, " && ") + ") || "
  2021. }
  2022. stmt = strings.TrimRight(stmt, " || ")
  2023. results += stmt
  2024. results += " {\n"
  2025. // return plural rule here
  2026. results += "return locales." + ps1 + "\n"
  2027. results += "}"
  2028. }
  2029. pre := "\n"
  2030. // always needed
  2031. vals[prVarFuncs["n"]] = struct{}{}
  2032. sorted := make([]sortRank, 0, len(vals))
  2033. for k := range vals {
  2034. switch k[:1] {
  2035. case "n":
  2036. sorted = append(sorted, sortRank{
  2037. Value: prVarFuncs["n"],
  2038. Rank: 1,
  2039. })
  2040. case "i":
  2041. sorted = append(sorted, sortRank{
  2042. Value: prVarFuncs["i"],
  2043. Rank: 2,
  2044. })
  2045. case "w":
  2046. sorted = append(sorted, sortRank{
  2047. Value: prVarFuncs["w"],
  2048. Rank: 3,
  2049. })
  2050. case "f":
  2051. sorted = append(sorted, sortRank{
  2052. Value: prVarFuncs["f"],
  2053. Rank: 4,
  2054. })
  2055. case "t":
  2056. sorted = append(sorted, sortRank{
  2057. Value: prVarFuncs["t"],
  2058. Rank: 5,
  2059. })
  2060. }
  2061. }
  2062. sort.Sort(ByRank(sorted))
  2063. for _, k := range sorted {
  2064. pre += k.Value
  2065. }
  2066. if len(results) == 0 {
  2067. results = "return locales.PluralRuleUnknown"
  2068. } else {
  2069. if !strings.HasPrefix(results, "return") {
  2070. results = manyToSingleVars(results)
  2071. // pre += "\n"
  2072. results = pre + results
  2073. }
  2074. }
  2075. if len(pluralArr) == 0 {
  2076. plurals = "nil"
  2077. } else {
  2078. plurals = fmt.Sprintf("%#v", pluralArr)
  2079. }
  2080. return
  2081. }
  2082. func manyToSingleVars(input string) (results string) {
  2083. matches := nModRegex.FindAllString(input, -1)
  2084. mp := make(map[string][]string) // map of formula to variable
  2085. var found bool
  2086. var split []string
  2087. var variable string
  2088. for _, formula := range matches {
  2089. if _, found = mp[formula]; found {
  2090. continue
  2091. }
  2092. split = strings.SplitN(formula, "%", 2)
  2093. mp[formula] = []string{split[1], "math.Mod(" + split[0] + ", " + split[1] + ")"}
  2094. }
  2095. for k, v := range mp {
  2096. variable = "nMod" + v[0]
  2097. results += variable + " := " + v[1] + "\n"
  2098. input = strings.Replace(input, k, variable, -1)
  2099. }
  2100. matches = iModRegex.FindAllString(input, -1)
  2101. mp = make(map[string][]string) // map of formula to variable
  2102. for _, formula := range matches {
  2103. if _, found = mp[formula]; found {
  2104. continue
  2105. }
  2106. split = strings.SplitN(formula, "%", 2)
  2107. mp[formula] = []string{split[1], formula}
  2108. }
  2109. for k, v := range mp {
  2110. variable = "iMod" + v[0]
  2111. results += variable + " := " + v[1] + "\n"
  2112. input = strings.Replace(input, k, variable, -1)
  2113. }
  2114. matches = wModRegex.FindAllString(input, -1)
  2115. mp = make(map[string][]string) // map of formula to variable
  2116. for _, formula := range matches {
  2117. if _, found = mp[formula]; found {
  2118. continue
  2119. }
  2120. split = strings.SplitN(formula, "%", 2)
  2121. mp[formula] = []string{split[1], formula}
  2122. }
  2123. for k, v := range mp {
  2124. variable = "wMod" + v[0]
  2125. results += variable + " := " + v[1] + "\n"
  2126. input = strings.Replace(input, k, variable, -1)
  2127. }
  2128. matches = fModRegex.FindAllString(input, -1)
  2129. mp = make(map[string][]string) // map of formula to variable
  2130. for _, formula := range matches {
  2131. if _, found = mp[formula]; found {
  2132. continue
  2133. }
  2134. split = strings.SplitN(formula, "%", 2)
  2135. mp[formula] = []string{split[1], formula}
  2136. }
  2137. for k, v := range mp {
  2138. variable = "fMod" + v[0]
  2139. results += variable + " := " + v[1] + "\n"
  2140. input = strings.Replace(input, k, variable, -1)
  2141. }
  2142. matches = tModRegex.FindAllString(input, -1)
  2143. mp = make(map[string][]string) // map of formula to variable
  2144. for _, formula := range matches {
  2145. if _, found = mp[formula]; found {
  2146. continue
  2147. }
  2148. split = strings.SplitN(formula, "%", 2)
  2149. mp[formula] = []string{split[1], formula}
  2150. }
  2151. for k, v := range mp {
  2152. variable = "tMod" + v[0]
  2153. results += variable + " := " + v[1] + "\n"
  2154. input = strings.Replace(input, k, variable, -1)
  2155. }
  2156. results = results + "\n" + input
  2157. return
  2158. }
  2159. // pluralStringToInt returns the enum value of 'plural' provided
  2160. func pluralStringToInt(plural string) locales.PluralRule {
  2161. switch plural {
  2162. case "zero":
  2163. return locales.PluralRuleZero
  2164. case "one":
  2165. return locales.PluralRuleOne
  2166. case "two":
  2167. return locales.PluralRuleTwo
  2168. case "few":
  2169. return locales.PluralRuleFew
  2170. case "many":
  2171. return locales.PluralRuleMany
  2172. case "other":
  2173. return locales.PluralRuleOther
  2174. default:
  2175. return locales.PluralRuleUnknown
  2176. }
  2177. }
  2178. func pluralStringToString(pr string) string {
  2179. pr = strings.TrimSpace(pr)
  2180. switch pr {
  2181. case "zero":
  2182. return "PluralRuleZero"
  2183. case "one":
  2184. return "PluralRuleOne"
  2185. case "two":
  2186. return "PluralRuleTwo"
  2187. case "few":
  2188. return "PluralRuleFew"
  2189. case "many":
  2190. return "PluralRuleMany"
  2191. case "other":
  2192. return "PluralRuleOther"
  2193. default:
  2194. return "PluralRuleUnknown"
  2195. }
  2196. }