// 2. Контроль зацикливаний тега tTagIncludeCon func chekloop(tpls map[string]parser.Ttpl) { var ( key string mitem = []interface{}{} ) matrix := make(map[interface{}][]interface{}, len(tpls)) for key = range tpls { for _, item := range tpls[key] { switch v := item.(type) { case tTagIncludeVar: if key == v[0] { err.Panic(err.New("Error: loops detection: "+key+" - "+key, 0)) } mitem = append(mitem, v[0]) } } if len(mitem) > 0 { matrix[key] = mitem } } loop := tarjan.Connections(matrix) for i := range loop { if len(loop[i]) > 1 { err.Panic(err.New("Error: loops detection: "+fmt.Sprint(loop[i]), 0)) } } }
func (t *TGen) decode(val reflect.Type) { v, ok := t.stackName.Pop() if !ok { err.Panic(err.New("stack name empty", 0)) } name := v.(string) switch val.Kind() { case reflect.Uint8: t.decUint8(name) case reflect.Uint16: t.decUint16(name) case reflect.Uint32: t.decUint32(name) case reflect.Uint64: t.decUint64(name) case reflect.Uint: t.decUint(name) case reflect.Int8: t.decInt8(name) case reflect.Int16: t.decInt16(name) case reflect.Int32: t.decInt32(name) case reflect.Int64: t.decInt64(name) case reflect.Int: t.decInt(name) case reflect.Float32: t.decFloat32(name) case reflect.Float64: t.decFloat64(name) case reflect.Complex64: t.decComplex64(name) case reflect.Complex128: t.decComplex128(name) case reflect.Bool: t.decBool(name) case reflect.String: t.decString(name) case reflect.Slice: t.decSlice(name, val) case reflect.Array: t.decArray(name, val) case reflect.Ptr: t.decPtr(name, val) case reflect.Struct: t.decStruct(name, val) case reflect.Map: t.decMap(name, val) case reflect.Interface: err.Panic(err.New("interface type not supported, only strong typed", 0)) } }
func (t *TReplaser) Replace(name string, v map[string]interface{}, writer io.Writer) { tpl := t.tpl.tpl[name] if tpl == nil { err.Panic(err.New("Err, tpl '"+name+"' not found", 0)) } t.replace(tpl, v, writer) }
// Call call function from a function map func (t FuncMap) Call(name string, params ...interface{}) []reflect.Value { f, e := t[name] if !e { err.Panic(err.New(errFunctionNotFound, 0)) } return call(f, params...) }
// Add add to function map func (t FuncMap) Add(name string, f interface{}) { v := reflect.ValueOf(f) if v.Kind() != reflect.Func { err.Panic(err.New(errNotFunction, 0)) } t[name] = v }
// NewReplacer Create new replacer from language resources func (t *Ti18n) NewReplacer(langName string) (*TReplacer, error) { lang, e := t.lang[langName] if !e { return nil, err.New("Not found lang resurse from langname: '"+langName+"'", 0) } return &TReplacer{langName: langName, lang: lang}, nil }
// Add add to function slice, return element id func (t *FuncSlice) Add(f interface{}) int { v := reflect.ValueOf(f) if v.Kind() != reflect.Func { err.Panic(err.New(errNotFunction, 0)) } *t = append(*t, v) return len(*t) - 1 }
// parse plural tag func parseTagPlural(source []string) *tTagPlural { if len(source) < 2 { err.Panic(err.New("error parsing to Plural Tag: "+fmt.Sprint(source), 0)) } i, e := strconv.ParseUint(source[1], 10, 16) err.Panic(e) return &tTagPlural{uint16(i), []string{source[0]}} }
func call(f reflect.Value, params ...interface{}) []reflect.Value { if len(params) != f.Type().NumIn() { err.Panic(err.New(errNumberParamsNotAdapted, 0)) } in := make([]reflect.Value, len(params)) for k, param := range params { in[k] = reflect.ValueOf(param) } return f.Call(in) }
// parseTagi18n func parseTagFor(source []string) interface{} { var m [2]string if len(source) < 3 { err.Panic(err.New("error parse tag 'For'", 0)) } if source[0][0] == 46 { if len(source[0]) > 1 { m[0] = source[0][1:] } else { m[0] = "." } return tTagi18nVar(m) } m[0] = source[0] return &tTagFor{} }
// 3. for a tTagIncludeCon init before use func (t *Ttpl) tagIncludeCon_Init() { for key, val := range t.tpl { for key1 := range val { switch v := val[key1].(type) { case tTagIncludeVar: // не полное имя и не имя переменной контекста - значит короткое имя if v[0][0] == 47 { tpl := t.tpl[v[0]] if tpl == nil { err.Panic(err.New("Err parse from tpl: '"+key+"' include tag. Not found tpl: '"+v[0]+"'", 0)) } val[key1] = &tTagIncludeCon{tpl: tpl, contextVar: v[1]} } } } } }
func parseTag(source []byte) interface{} { defer func() { if e := recover(); e != nil { panic(err.New("err parse i18n: "+string(source), 0)) } }() list := parser.SplitWord(source, 32) switch list[0] { case "plural": return parseTagPlural(list[1:]) case "f": return parseTagFunc(list[1:]) default: return parseTagVar(list) } }
func (t *TGen) encode(val reflect.Type) { v, ok := t.stackName.Pop() if !ok { err.Panic(err.New("stack name empty", 0)) } name := v.(string) // use json.Marshaler implement if val.Implements(MarshalerType) { tmpName := t.tmpNameGen.Get() // get tmp var name t.src += "tmpName, _ := " + name + ".MarshalJSON()\n" t.src += "buf = append(buf, " + tmpName + ")\n" return } switch val.Kind() { case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: t.genUint(name) case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Int: t.genInt(name) case reflect.Float32, reflect.Float64: t.genFloat(name) case reflect.Bool: t.genBool(name) case reflect.String: t.genString(name) case reflect.Slice: t.genSlice(name, val) case reflect.Array: t.genArray(name, val) case reflect.Ptr: t.genPtr(name, val) case reflect.Struct: t.genStruct(name, val) case reflect.Map: t.genMap(name, val) case reflect.Interface: t.genInterface(name, val) } }
// Get phrase func (t *TReplacer) p(tpl *titem, context []interface{}) []byte { var ( varFloate float64 varBool bool varUint16 uint16 result []byte ) if int(tpl.contextCount) > len(context) { err.Panic(err.New("i18n Mismatch context len: ("+strconv.Itoa(int(tpl.contextCount))+" , "+strconv.Itoa(len(context))+") "+fmt.Sprintf("%#v", tpl.items), 0)) } for _, item := range tpl.items { switch v := item.(type) { case tTagText: result = append(result, v...) case *tTagVar: if len(v.format) > 0 { result = append(result, []byte(fmt.Sprintf(v.format, context[v.id]))...) } else { result = append(result, []byte(fmt.Sprint(context[v.id]))...) } case *tTagPlural: varFloate, varBool = refl.Floate(context[v.count]) if varBool { result = append(result, []byte(v.text[t.lang.PluralRule(varFloate)])...) } case *tTagFunction: var vars []interface{} for _, varUint16 = range v.vars { vars = append(vars, context[varUint16]) } result = append(result, v.f(vars)...) } } return result }
// Call call function from a function slice func (t FuncSlice) Call(id int, params ...interface{}) []reflect.Value { if len(t) <= id { err.Panic(err.New(errFunctionNotFound, 0)) } return call(t[id], params...) }
// Load load language resources func (t *Ti18n) Load(patch string) { type ( tmpLang struct { PluralRule string Plural map[string][]string Phrase map[string]string Lists map[string][]string } ) // создаётся временная структура и в неё парсится json tmpLangs := make(map[string]*tmpLang) fileList, e := ioutil.ReadDir(patch) err.Panic(e) var ( name string valPre map[string]string keyPre string ) for _, item := range fileList { vtmpLang := new(tmpLang) vtmpLang.Plural = make(map[string][]string) vtmpLang.Lists = make(map[string][]string) jsonConfig.Load(patch+string(filepath.Separator)+item.Name(), &vtmpLang) name, _ = gfilepath.Ext(item.Name()) tmpLangs[name] = vtmpLang } // chek equivalent all lang resurce for key, val := range tmpLangs { if valPre != nil && !refl.MapKeysEq(valPre, val.Phrase) { err.Panic(err.New("Lang phrase not equivalent: "+keyPre+", "+key, 0)) } valPre = val.Phrase keyPre = key } toparse := new(parser.ToParse) toparse.Delimiter[0] = []byte("{{") toparse.Delimiter[1] = []byte("}}") toparse.ParseTag = parseTag toparse.ParseText = parseText for key, item := range tmpLangs { lang := &Tlang{ items: make(map[string]*titem), Plural: item.Plural, Lists: item.Lists, PluralRule: plural.PluralRules[item.PluralRule], F: make(map[string]func([]interface{}) []byte), } if lang.PluralRule == nil && len(lang.Plural) > 0 { err.Panic(err.New("Not found plural rule: '"+item.PluralRule+"'", 0)) } for keyPhrase, itemPhrase := range item.Phrase { lang.items[keyPhrase] = &titem{items: parser.Parse([]byte(itemPhrase), toparse), contextCount: -1} } existLang := t.lang[key] if existLang == nil { t.lang[key] = lang } else { // add phrase for key, val := range lang.items { existLang.items[key] = val } // add plural for key, val := range lang.Plural { existLang.Plural[key] = val } // add lists for key, val := range lang.Lists { existLang.Lists[key] = val } } } }